move classmapping to DB
LearningPointsData transfered to DataBase
This commit is contained in:
+60
-273
@@ -3080,289 +3080,76 @@ func GetCharacterClassLearningPoints(c *gin.Context) {
|
||||
|
||||
// getLearningPointsForClass gibt die Lernpunkte-Daten für eine bestimmte Charakterklasse zurück
|
||||
func getLearningPointsForClass(className string, stand string) (*LearningPointsData, error) {
|
||||
// Mapping der Klassennamen zu Codes (falls notwendig)
|
||||
classMapping := map[string]string{
|
||||
"Assassine": "As",
|
||||
"Barbar": "Bb",
|
||||
"Glücksritter": "Gl",
|
||||
"Händler": "Hä",
|
||||
"Krieger": "Kr",
|
||||
"Spitzbube": "Sp",
|
||||
"Waldläufer": "Wa",
|
||||
"Barde": "Ba",
|
||||
"Ordenskrieger": "Or",
|
||||
"Druide": "Dr",
|
||||
"Hexer": "Hx",
|
||||
"Magier": "Ma",
|
||||
"Priester Beschützer": "PB",
|
||||
"Priester Streiter": "PS",
|
||||
"Schamane": "Sc",
|
||||
// Get character class from database by name or code
|
||||
var charClass models.CharacterClass
|
||||
result := database.DB.Where("name = ? OR code = ?", className, className).First(&charClass)
|
||||
if result.Error != nil {
|
||||
return nil, fmt.Errorf("character class not found: %s", className)
|
||||
}
|
||||
|
||||
classCode := classMapping[className]
|
||||
if classCode == "" {
|
||||
classCode = className // Falls der Name bereits ein Code ist
|
||||
// Get learning points from database
|
||||
learningPoints, err := models.GetLearningPointsForClass(charClass.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get learning points: %w", err)
|
||||
}
|
||||
|
||||
// Definiere die Lernpunkte-Daten basierend auf Lerntabelle_Erstellung.md
|
||||
var data *LearningPointsData
|
||||
// Convert to map format
|
||||
learningPointsMap := make(map[string]int)
|
||||
for _, lp := range learningPoints {
|
||||
learningPointsMap[lp.SkillCategory.Name] = lp.Points
|
||||
}
|
||||
|
||||
switch classCode {
|
||||
case "As", "Assassine":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Assassine",
|
||||
ClassCode: "As",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 1,
|
||||
"Halbwelt": 2,
|
||||
"Sozial": 4,
|
||||
"Unterwelt": 8,
|
||||
"Waffen": 24,
|
||||
},
|
||||
//WeaponPoints: 24,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Meucheln", Bonus: 8, Attribute: "Gs", Notes: ""},
|
||||
},
|
||||
// Get spell points if applicable
|
||||
spellPoints, err := models.GetSpellPointsForClass(charClass.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get spell points: %w", err)
|
||||
}
|
||||
|
||||
// Get typical skills
|
||||
typicalSkillsDB, err := models.GetTypicalSkillsForClass(charClass.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get typical skills: %w", err)
|
||||
}
|
||||
|
||||
// Convert typical skills
|
||||
typicalSkills := make([]TypicalSkill, len(typicalSkillsDB))
|
||||
for i, ts := range typicalSkillsDB {
|
||||
typicalSkills[i] = TypicalSkill{
|
||||
Name: ts.Skill.Name,
|
||||
Bonus: ts.Bonus,
|
||||
Attribute: ts.Attribute,
|
||||
Notes: ts.Notes,
|
||||
}
|
||||
case "Bb", "Barbar":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Barbar",
|
||||
ClassCode: "Bb",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Freiland": 4,
|
||||
"Kampf": 1,
|
||||
"Körper": 2,
|
||||
"Waffen": 24,
|
||||
},
|
||||
//WeaponPoints: 24,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Spurensuche", Bonus: 8, Attribute: "In", Notes: "in Heimatlandschaft"},
|
||||
{Name: "Überleben", Bonus: 8, Attribute: "In", Notes: "in Heimatlandschaft"},
|
||||
},
|
||||
}
|
||||
|
||||
// Get typical spells
|
||||
typicalSpellsDB, err := models.GetTypicalSpellsForClass(charClass.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get typical spells: %w", err)
|
||||
}
|
||||
|
||||
// Convert typical spells
|
||||
typicalSpells := make([]string, len(typicalSpellsDB))
|
||||
for i, ts := range typicalSpellsDB {
|
||||
spellName := ts.Spell.Name
|
||||
if ts.Notes != "" {
|
||||
spellName = ts.Notes // Use notes for special cases like "beliebig außer..."
|
||||
}
|
||||
case "Gl", "Glücksritter":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Glücksritter",
|
||||
ClassCode: "Gl",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Halbwelt": 3,
|
||||
"Sozial": 8,
|
||||
"Waffen": 24,
|
||||
},
|
||||
//WeaponPoints: 24,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Fechten", Bonus: 5, Attribute: "Gs", Notes: "oder beidhändiger Kampf+5 (Gs)"},
|
||||
},
|
||||
}
|
||||
case "Hä", "Händler":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Händler",
|
||||
ClassCode: "Hä",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 4,
|
||||
"Sozial": 8,
|
||||
"Wissen": 4,
|
||||
"Waffen": 20,
|
||||
},
|
||||
//WeaponPoints: 20,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Geschäftssinn", Bonus: 8, Attribute: "In", Notes: ""},
|
||||
},
|
||||
}
|
||||
case "Kr", "Krieger":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Krieger",
|
||||
ClassCode: "Kr",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Kampf": 3,
|
||||
"Körper": 1,
|
||||
"Waffen": 36,
|
||||
},
|
||||
//WeaponPoints: 36,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Kampf in Vollrüstung", Bonus: 5, Attribute: "St", Notes: ""},
|
||||
},
|
||||
}
|
||||
case "Sp", "Spitzbube":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Spitzbube",
|
||||
ClassCode: "Sp",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Halbwelt": 6,
|
||||
"Unterwelt": 12,
|
||||
"Waffen": 20,
|
||||
},
|
||||
//WeaponPoints: 20,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Fallenmechanik", Bonus: 8, Attribute: "Gs", Notes: "oder Geschäftssinn+8 (In)"},
|
||||
},
|
||||
}
|
||||
case "Wa", "Waldläufer":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Waldläufer",
|
||||
ClassCode: "Wa",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 1,
|
||||
"Freiland": 11,
|
||||
"Körper": 4,
|
||||
"Waffen": 20,
|
||||
},
|
||||
//WeaponPoints: 20,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Scharfschießen", Bonus: 5, Attribute: "Gs", Notes: ""},
|
||||
},
|
||||
}
|
||||
case "Ba", "Barde":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Barde",
|
||||
ClassCode: "Ba",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Sozial": 4,
|
||||
"Wissen": 4,
|
||||
"Waffen": 16,
|
||||
},
|
||||
//WeaponPoints: 16,
|
||||
SpellPoints: 3,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Musizieren", Bonus: 12, Attribute: "Gs", Notes: ""},
|
||||
{Name: "Landeskunde", Bonus: 8, Attribute: "In", Notes: "für Heimat"},
|
||||
},
|
||||
TypicalSpells: []string{"Zauberlieder"},
|
||||
}
|
||||
case "Or", "Ordenskrieger":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Ordenskrieger",
|
||||
ClassCode: "Or",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Kampf": 3,
|
||||
"Wissen": 2,
|
||||
"Waffen": 18,
|
||||
},
|
||||
//WeaponPoints: 18,
|
||||
SpellPoints: 3,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Athletik", Bonus: 8, Attribute: "St", Notes: "oder Meditieren+8 (Wk)"},
|
||||
},
|
||||
TypicalSpells: []string{"Wundertaten"},
|
||||
}
|
||||
case "Dr", "Druide":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Druide",
|
||||
ClassCode: "Dr",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Freiland": 4,
|
||||
"Wissen": 2,
|
||||
"Waffen": 6,
|
||||
},
|
||||
//WeaponPoints: 6,
|
||||
SpellPoints: 5,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Pflanzenkunde", Bonus: 8, Attribute: "In", Notes: ""},
|
||||
{Name: "Schreiben", Bonus: 12, Attribute: "In", Notes: "für Ogam-Zeichen"},
|
||||
},
|
||||
TypicalSpells: []string{"Dweomer", "Tiere rufen"},
|
||||
}
|
||||
case "Hx", "Hexer":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Hexer",
|
||||
ClassCode: "Hx",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 3,
|
||||
"Sozial": 2,
|
||||
"Wissen": 2,
|
||||
"Waffen": 2,
|
||||
},
|
||||
//WeaponPoints: 2,
|
||||
SpellPoints: 6,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Gassenwissen", Bonus: 8, Attribute: "In", Notes: "oder Verführen+8 (pA)"},
|
||||
},
|
||||
TypicalSpells: []string{"Beherrschen", "Verändern", "Verwünschen", "Binden des Vertrauten"},
|
||||
}
|
||||
case "Ma", "Magier":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Magier",
|
||||
ClassCode: "Ma",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 1,
|
||||
"Wissen": 5,
|
||||
"Waffen": 2,
|
||||
},
|
||||
//WeaponPoints: 2,
|
||||
SpellPoints: 7,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Zauberkunde", Bonus: 8, Attribute: "In", Notes: ""},
|
||||
{Name: "Schreiben", Bonus: 12, Attribute: "In", Notes: "für Muttersprache"},
|
||||
},
|
||||
TypicalSpells: []string{"beliebig außer Dweomer, Wundertaten, Zauberlieder", "Erkennen von Zauberei"},
|
||||
}
|
||||
case "PB", "Priester Beschützer":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Priester Beschützer",
|
||||
ClassCode: "PB",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Sozial": 2,
|
||||
"Wissen": 3,
|
||||
"Waffen": 6,
|
||||
},
|
||||
//WeaponPoints: 6,
|
||||
SpellPoints: 5,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Menschenkenntnis", Bonus: 8, Attribute: "In", Notes: ""},
|
||||
{Name: "Schreiben", Bonus: 12, Attribute: "In", Notes: "für Muttersprache"},
|
||||
},
|
||||
TypicalSpells: []string{"Wundertaten", "Heilen von Wunden"},
|
||||
}
|
||||
case "PS", "Priester Streiter":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Priester Streiter",
|
||||
ClassCode: "PS",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 3,
|
||||
"Kampf": 2,
|
||||
"Wissen": 2,
|
||||
"Waffen": 8,
|
||||
},
|
||||
//WeaponPoints: 8,
|
||||
SpellPoints: 5,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Erste Hilfe", Bonus: 8, Attribute: "Gs", Notes: ""},
|
||||
{Name: "Schreiben", Bonus: 12, Attribute: "In", Notes: "für Muttersprache"},
|
||||
},
|
||||
TypicalSpells: []string{"Wundertaten", "Bannen von Finsterwerk", "Strahlender Panzer"},
|
||||
}
|
||||
case "Sc", "Schamane":
|
||||
data = &LearningPointsData{
|
||||
ClassName: "Schamane",
|
||||
ClassCode: "Sc",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Körper": 4,
|
||||
"Wissen": 2,
|
||||
"Waffen": 6,
|
||||
},
|
||||
//WeaponPoints: 6,
|
||||
SpellPoints: 5,
|
||||
TypicalSkills: []TypicalSkill{
|
||||
{Name: "Tierkunde", Bonus: 8, Attribute: "In", Notes: ""},
|
||||
{Name: "Überleben", Bonus: 8, Attribute: "In", Notes: "in Heimatlandschaft"},
|
||||
},
|
||||
TypicalSpells: []string{"Dweomer", "Wundertaten", "Austreibung des Bösen", "Bannen von Gift"},
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unbekannte Charakterklasse: %s", className)
|
||||
typicalSpells[i] = spellName
|
||||
}
|
||||
|
||||
// Build the response data
|
||||
data := &LearningPointsData{
|
||||
ClassName: charClass.Name,
|
||||
ClassCode: charClass.Code,
|
||||
LearningPoints: learningPointsMap,
|
||||
SpellPoints: spellPoints.SpellPoints,
|
||||
TypicalSkills: typicalSkills,
|
||||
TypicalSpells: typicalSpells,
|
||||
}
|
||||
|
||||
// Bonus-Lernpunkte basierend auf Stand hinzufügen
|
||||
if stand != "" && data != nil {
|
||||
if stand != "" {
|
||||
standBonus := getStandBonusPoints(stand)
|
||||
// Füge die Stand-Bonuspunkte zu den normalen Lernpunkten hinzu
|
||||
for category, bonus := range standBonus {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package character
|
||||
|
||||
import (
|
||||
"bamort/database"
|
||||
"bamort/models"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -11,6 +13,20 @@ import (
|
||||
)
|
||||
|
||||
func TestGetCharacterClassLearningPoints(t *testing.T) {
|
||||
// Setup test database
|
||||
database.SetupTestDB()
|
||||
|
||||
// Migrate the new structures
|
||||
if err := models.MigrateStructure(database.DB); err != nil {
|
||||
t.Fatalf("Failed to migrate structures: %v", err)
|
||||
}
|
||||
|
||||
// Populate test data (character classes and learning points)
|
||||
if err := models.PopulateClassLearningPointsData(); err != nil {
|
||||
t.Logf("Warning: Failed to populate learning points data: %v", err)
|
||||
// Continue anyway - some tests may still work
|
||||
}
|
||||
|
||||
// Setup Gin in test mode
|
||||
gin.SetMode(gin.TestMode)
|
||||
router := gin.New()
|
||||
@@ -169,9 +185,9 @@ func TestGetCharacterClassLearningPoints(t *testing.T) {
|
||||
assert.NotNil(t, response.LearningPoints)
|
||||
assert.NotNil(t, response.TypicalSkills)
|
||||
|
||||
// Check weapon points if specified
|
||||
// Check weapon points if specified (now in LearningPoints["Waffen"])
|
||||
if tt.checkWeapons {
|
||||
assert.Equal(t, tt.expectedWeapons, response.WeaponPoints)
|
||||
assert.Equal(t, tt.expectedWeapons, response.LearningPoints["Waffen"], "Weapon learning points should match")
|
||||
}
|
||||
|
||||
// Check spell points if specified
|
||||
@@ -191,6 +207,19 @@ func TestGetCharacterClassLearningPoints(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetLearningPointsForClass(t *testing.T) {
|
||||
// Setup test database
|
||||
database.SetupTestDB()
|
||||
|
||||
// Migrate the new structures
|
||||
if err := models.MigrateStructure(database.DB); err != nil {
|
||||
t.Fatalf("Failed to migrate structures: %v", err)
|
||||
}
|
||||
|
||||
// Populate test data
|
||||
if err := models.PopulateClassLearningPointsData(); err != nil {
|
||||
t.Logf("Warning: Failed to populate learning points data: %v", err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
className string
|
||||
@@ -354,6 +383,19 @@ func TestGetStandBonusPoints(t *testing.T) {
|
||||
|
||||
// Test all character classes to ensure they're properly defined
|
||||
func TestAllCharacterClassesAreDefined(t *testing.T) {
|
||||
// Setup test database
|
||||
database.SetupTestDB()
|
||||
|
||||
// Migrate the new structures
|
||||
if err := models.MigrateStructure(database.DB); err != nil {
|
||||
t.Fatalf("Failed to migrate structures: %v", err)
|
||||
}
|
||||
|
||||
// Populate test data
|
||||
if err := models.PopulateClassLearningPointsData(); err != nil {
|
||||
t.Logf("Warning: Failed to populate learning points data: %v", err)
|
||||
}
|
||||
|
||||
expectedClasses := []string{
|
||||
"Assassine", "Barbar", "Glücksritter", "Händler", "Krieger", "Spitzbube", "Waldläufer",
|
||||
"Barde", "Ordenskrieger", "Druide", "Hexer", "Magier", "Priester Beschützer", "Priester Streiter", "Schamane",
|
||||
|
||||
@@ -219,6 +219,10 @@ func copyMariaDBToSQLite(mariaDB, sqliteDB *gorm.DB) error {
|
||||
&models.SkillCategoryDifficulty{},
|
||||
&models.WeaponSkillCategoryDifficulty{},
|
||||
&models.SkillImprovementCost{},
|
||||
&models.ClassLearningPoints{},
|
||||
&models.ClassSpellPoints{},
|
||||
&models.ClassTypicalSkill{},
|
||||
&models.ClassTypicalSpell{},
|
||||
|
||||
// GSMaster Basis-Daten
|
||||
//&models.LookupList{}, // Basis für Skills, Spells, Equipment
|
||||
@@ -561,6 +565,22 @@ func SetupCheckDev(c *gin.Context) {
|
||||
logger.Info("Setup-Check erfolgreich abgeschlossen")
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Setup Check OK"})
|
||||
}
|
||||
|
||||
// PopulateClassLearningPoints populates the class learning points tables from hardcoded data
|
||||
func PopulateClassLearningPoints(c *gin.Context) {
|
||||
logger.Info("Starte Population der Class Learning Points Daten...")
|
||||
|
||||
err := models.PopulateClassLearningPointsData()
|
||||
if err != nil {
|
||||
logger.Error("Fehler beim Populieren der Class Learning Points: %s", err.Error())
|
||||
respondWithError(c, http.StatusInternalServerError, "Failed to populate class learning points: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("Class Learning Points erfolgreich populiert")
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Class learning points data populated successfully"})
|
||||
}
|
||||
|
||||
func ReconnectDataBase(c *gin.Context) {
|
||||
logger.Info("Führe Datenbank-Reconnect durch...")
|
||||
|
||||
@@ -735,6 +755,10 @@ func copySQLiteToMariaDB(sqliteDB, mariaDB *gorm.DB) error {
|
||||
&models.SkillCategoryDifficulty{}, // Jetzt nach Skills
|
||||
&models.WeaponSkillCategoryDifficulty{},
|
||||
&models.SkillImprovementCost{},
|
||||
&models.ClassLearningPoints{},
|
||||
&models.ClassSpellPoints{},
|
||||
&models.ClassTypicalSkill{},
|
||||
&models.ClassTypicalSpell{},
|
||||
|
||||
// Charaktere (Basis)
|
||||
&models.Char{},
|
||||
@@ -889,6 +913,30 @@ func copyTableDataReverse(sourceDB, targetDB *gorm.DB, model interface{}) error
|
||||
return fmt.Errorf("failed to read batch from source: %w", err)
|
||||
}
|
||||
records = batch
|
||||
case *models.ClassLearningPoints:
|
||||
var batch []models.ClassLearningPoints
|
||||
if err := sourceDB.Limit(batchSize).Offset(offset).Find(&batch).Error; err != nil {
|
||||
return fmt.Errorf("failed to read batch from source: %w", err)
|
||||
}
|
||||
records = batch
|
||||
case *models.ClassSpellPoints:
|
||||
var batch []models.ClassSpellPoints
|
||||
if err := sourceDB.Limit(batchSize).Offset(offset).Find(&batch).Error; err != nil {
|
||||
return fmt.Errorf("failed to read batch from source: %w", err)
|
||||
}
|
||||
records = batch
|
||||
case *models.ClassTypicalSkill:
|
||||
var batch []models.ClassTypicalSkill
|
||||
if err := sourceDB.Limit(batchSize).Offset(offset).Find(&batch).Error; err != nil {
|
||||
return fmt.Errorf("failed to read batch from source: %w", err)
|
||||
}
|
||||
records = batch
|
||||
case *models.ClassTypicalSpell:
|
||||
var batch []models.ClassTypicalSpell
|
||||
if err := sourceDB.Limit(batchSize).Offset(offset).Find(&batch).Error; err != nil {
|
||||
return fmt.Errorf("failed to read batch from source: %w", err)
|
||||
}
|
||||
records = batch
|
||||
case *models.Skill:
|
||||
var batch []models.Skill
|
||||
if err := sourceDB.Limit(batchSize).Offset(offset).Find(&batch).Error; err != nil {
|
||||
@@ -1104,6 +1152,10 @@ func clearMariaDBData(db *gorm.DB) error {
|
||||
&models.SpellLevelLECost{},
|
||||
&models.ClassSpellSchoolEPCost{},
|
||||
&models.ClassCategoryEPCost{},
|
||||
&models.ClassTypicalSpell{},
|
||||
&models.ClassTypicalSkill{},
|
||||
&models.ClassSpellPoints{},
|
||||
&models.ClassLearningPoints{},
|
||||
|
||||
// GSMaster Basis-Daten
|
||||
&models.Believe{},
|
||||
|
||||
@@ -15,7 +15,8 @@ func RegisterRoutes(r *gin.RouterGroup) {
|
||||
charGrp.GET("/mktestdata", MakeTestdataFromLive)
|
||||
charGrp.GET("/reconndb", ReconnectDataBase) // Datenbank neu verbinden
|
||||
charGrp.GET("/reloadenv", ReloadENV)
|
||||
charGrp.POST("/transfer-sqlite-to-mariadb", TransferSQLiteToMariaDB) // Transfer data from SQLite to MariaDB
|
||||
charGrp.POST("/transfer-sqlite-to-mariadb", TransferSQLiteToMariaDB) // Transfer data from SQLite to MariaDB
|
||||
charGrp.POST("/populate-class-learning-points", PopulateClassLearningPoints) // Populate class learning points from hardcoded data
|
||||
/*
|
||||
//nur zur einmaligen Ausführung, um das Lernkosten-System zu initialisieren
|
||||
charGrp.POST("/initialize-learning-costs", InitializeLearningCosts)
|
||||
|
||||
@@ -157,6 +157,10 @@ func learningMigrateStructure(db ...*gorm.DB) error {
|
||||
&SkillCategoryDifficulty{},
|
||||
&WeaponSkillCategoryDifficulty{},
|
||||
&SkillImprovementCost{},
|
||||
&ClassLearningPoints{},
|
||||
&ClassSpellPoints{},
|
||||
&ClassTypicalSkill{},
|
||||
&ClassTypicalSpell{},
|
||||
&AuditLogEntry{},
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"bamort/database"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// ClassLearningPoints stores the learning points distribution for a character class
|
||||
type ClassLearningPoints struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
CharacterClassID uint `gorm:"uniqueIndex:idx_class_category;not null" json:"character_class_id"`
|
||||
SkillCategoryID uint `gorm:"uniqueIndex:idx_class_category;not null" json:"skill_category_id"`
|
||||
Points int `gorm:"not null;default:0" json:"points"`
|
||||
CharacterClass CharacterClass `gorm:"foreignKey:CharacterClassID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"character_class"`
|
||||
SkillCategory SkillCategory `gorm:"foreignKey:SkillCategoryID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"skill_category"`
|
||||
}
|
||||
|
||||
// ClassSpellPoints stores the spell learning points for a character class
|
||||
type ClassSpellPoints struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
CharacterClassID uint `gorm:"uniqueIndex;not null" json:"character_class_id"`
|
||||
SpellPoints int `gorm:"not null;default:0" json:"spell_points"` // Zauberlerneinheiten
|
||||
CharacterClass CharacterClass `gorm:"foreignKey:CharacterClassID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"character_class"`
|
||||
}
|
||||
|
||||
// ClassTypicalSkill stores typical skills for a character class with bonuses
|
||||
type ClassTypicalSkill struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
CharacterClassID uint `gorm:"not null;index" json:"character_class_id"`
|
||||
SkillID uint `gorm:"not null;index" json:"skill_id"`
|
||||
Bonus int `gorm:"not null;default:0" json:"bonus"`
|
||||
Attribute string `gorm:"size:10" json:"attribute,omitempty"` // z.B. "Gs", "In", "St"
|
||||
Notes string `json:"notes,omitempty"` // Zusätzliche Notizen
|
||||
CharacterClass CharacterClass `gorm:"foreignKey:CharacterClassID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"character_class"`
|
||||
Skill Skill `gorm:"foreignKey:SkillID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"skill"`
|
||||
}
|
||||
|
||||
// ClassTypicalSpell stores typical spells for a character class
|
||||
type ClassTypicalSpell struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
CharacterClassID uint `gorm:"not null;index" json:"character_class_id"`
|
||||
SpellID uint `gorm:"not null;index" json:"spell_id"`
|
||||
Notes string `json:"notes,omitempty"` // z.B. "beliebig außer Dweomer"
|
||||
CharacterClass CharacterClass `gorm:"foreignKey:CharacterClassID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"character_class"`
|
||||
Spell Spell `gorm:"foreignKey:SpellID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"spell"`
|
||||
}
|
||||
|
||||
// TableName specifies the table name for ClassLearningPoints
|
||||
func (ClassLearningPoints) TableName() string {
|
||||
return "class_learning_points"
|
||||
}
|
||||
|
||||
// TableName specifies the table name for ClassSpellPoints
|
||||
func (ClassSpellPoints) TableName() string {
|
||||
return "class_spell_points"
|
||||
}
|
||||
|
||||
// TableName specifies the table name for ClassTypicalSkill
|
||||
func (ClassTypicalSkill) TableName() string {
|
||||
return "class_typical_skills"
|
||||
}
|
||||
|
||||
// TableName specifies the table name for ClassTypicalSpell
|
||||
func (ClassTypicalSpell) TableName() string {
|
||||
return "class_typical_spells"
|
||||
}
|
||||
|
||||
// GetLearningPointsForClass retrieves all learning points for a character class
|
||||
func GetLearningPointsForClass(classID uint) ([]ClassLearningPoints, error) {
|
||||
var points []ClassLearningPoints
|
||||
err := database.DB.Preload("SkillCategory").Where("character_class_id = ?", classID).Find(&points).Error
|
||||
return points, err
|
||||
}
|
||||
|
||||
// GetSpellPointsForClass retrieves spell points for a character class
|
||||
func GetSpellPointsForClass(classID uint) (*ClassSpellPoints, error) {
|
||||
var points ClassSpellPoints
|
||||
err := database.DB.Where("character_class_id = ?", classID).First(&points).Error
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return &ClassSpellPoints{SpellPoints: 0}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &points, nil
|
||||
}
|
||||
|
||||
// GetTypicalSkillsForClass retrieves typical skills for a character class
|
||||
func GetTypicalSkillsForClass(classID uint) ([]ClassTypicalSkill, error) {
|
||||
var skills []ClassTypicalSkill
|
||||
err := database.DB.Preload("Skill").Where("character_class_id = ?", classID).Find(&skills).Error
|
||||
return skills, err
|
||||
}
|
||||
|
||||
// GetTypicalSpellsForClass retrieves typical spells for a character class
|
||||
func GetTypicalSpellsForClass(classID uint) ([]ClassTypicalSpell, error) {
|
||||
var spells []ClassTypicalSpell
|
||||
err := database.DB.Preload("Spell").Where("character_class_id = ?", classID).Find(&spells).Error
|
||||
return spells, err
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"bamort/database"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// PopulateClassLearningPointsData inserts all hardcoded learning points data into the database
|
||||
func PopulateClassLearningPointsData() error {
|
||||
// Define all character class learning data
|
||||
classData := []struct {
|
||||
ClassCode string
|
||||
ClassName string
|
||||
LearningPoints map[string]int
|
||||
SpellPoints int
|
||||
TypicalSkills []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}
|
||||
TypicalSpells []string
|
||||
}{
|
||||
{
|
||||
ClassCode: "As",
|
||||
ClassName: "Assassine",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 1,
|
||||
"Halbwelt": 2,
|
||||
"Sozial": 4,
|
||||
"Unterwelt": 8,
|
||||
"Waffen": 24,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Meucheln", Bonus: 8, Attribute: "Gs", Notes: ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
ClassCode: "Bb",
|
||||
ClassName: "Barbar",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Freiland": 4,
|
||||
"Kampf": 1,
|
||||
"Körper": 2,
|
||||
"Waffen": 24,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Spurensuche", Bonus: 8, Attribute: "In", Notes: "in Heimatlandschaft"},
|
||||
{Name: "Überleben", Bonus: 8, Attribute: "In", Notes: "in Heimatlandschaft"},
|
||||
},
|
||||
},
|
||||
{
|
||||
ClassCode: "Gl",
|
||||
ClassName: "Glücksritter",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Halbwelt": 3,
|
||||
"Sozial": 8,
|
||||
"Waffen": 24,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Fechten", Bonus: 5, Attribute: "Gs", Notes: "oder beidhändiger Kampf+5 (Gs)"},
|
||||
},
|
||||
},
|
||||
{
|
||||
ClassCode: "Hä",
|
||||
ClassName: "Händler",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 4,
|
||||
"Sozial": 8,
|
||||
"Wissen": 4,
|
||||
"Waffen": 20,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Geschäftssinn", Bonus: 8, Attribute: "In", Notes: ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
ClassCode: "Kr",
|
||||
ClassName: "Krieger",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Kampf": 3,
|
||||
"Körper": 1,
|
||||
"Waffen": 36,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Kampf in Vollrüstung", Bonus: 5, Attribute: "St", Notes: ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
ClassCode: "Sp",
|
||||
ClassName: "Spitzbube",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Halbwelt": 6,
|
||||
"Unterwelt": 12,
|
||||
"Waffen": 20,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Fallenmechanik", Bonus: 8, Attribute: "Gs", Notes: "oder Geschäftssinn+8 (In)"},
|
||||
},
|
||||
},
|
||||
{
|
||||
ClassCode: "Wa",
|
||||
ClassName: "Waldläufer",
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 1,
|
||||
"Freiland": 11,
|
||||
"Körper": 4,
|
||||
"Waffen": 20,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Scharfschießen", Bonus: 5, Attribute: "Gs", Notes: ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
ClassCode: "Ba",
|
||||
ClassName: "Barde",
|
||||
SpellPoints: 3,
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Sozial": 4,
|
||||
"Wissen": 4,
|
||||
"Waffen": 16,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Musizieren", Bonus: 12, Attribute: "Gs", Notes: ""},
|
||||
{Name: "Landeskunde", Bonus: 8, Attribute: "In", Notes: "für Heimat"},
|
||||
},
|
||||
TypicalSpells: []string{"Zauberlieder"},
|
||||
},
|
||||
{
|
||||
ClassCode: "Or",
|
||||
ClassName: "Ordenskrieger",
|
||||
SpellPoints: 3,
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Kampf": 3,
|
||||
"Wissen": 2,
|
||||
"Waffen": 18,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Athletik", Bonus: 8, Attribute: "St", Notes: "oder Meditieren+8 (Wk)"},
|
||||
},
|
||||
TypicalSpells: []string{"Wundertaten"},
|
||||
},
|
||||
{
|
||||
ClassCode: "Dr",
|
||||
ClassName: "Druide",
|
||||
SpellPoints: 5,
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Freiland": 4,
|
||||
"Wissen": 2,
|
||||
"Waffen": 6,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Pflanzenkunde", Bonus: 8, Attribute: "In", Notes: ""},
|
||||
{Name: "Schreiben", Bonus: 12, Attribute: "In", Notes: "für Ogam-Zeichen"},
|
||||
},
|
||||
TypicalSpells: []string{"Dweomer", "Tiere rufen"},
|
||||
},
|
||||
{
|
||||
ClassCode: "Hx",
|
||||
ClassName: "Hexer",
|
||||
SpellPoints: 6,
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 3,
|
||||
"Sozial": 2,
|
||||
"Wissen": 2,
|
||||
"Waffen": 2,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Gassenwissen", Bonus: 8, Attribute: "In", Notes: "oder Verführen+8 (pA)"},
|
||||
},
|
||||
TypicalSpells: []string{"Beherrschen", "Verändern", "Verwünschen", "Binden des Vertrauten"},
|
||||
},
|
||||
{
|
||||
ClassCode: "Ma",
|
||||
ClassName: "Magier",
|
||||
SpellPoints: 7,
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 1,
|
||||
"Wissen": 5,
|
||||
"Waffen": 2,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Zauberkunde", Bonus: 8, Attribute: "In", Notes: ""},
|
||||
{Name: "Schreiben", Bonus: 12, Attribute: "In", Notes: "für Muttersprache"},
|
||||
},
|
||||
TypicalSpells: []string{"beliebig außer Dweomer, Wundertaten, Zauberlieder", "Erkennen von Zauberei"},
|
||||
},
|
||||
{
|
||||
ClassCode: "PB",
|
||||
ClassName: "Priester Beschützer",
|
||||
SpellPoints: 5,
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Sozial": 2,
|
||||
"Wissen": 3,
|
||||
"Waffen": 6,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Menschenkenntnis", Bonus: 8, Attribute: "In", Notes: ""},
|
||||
{Name: "Schreiben", Bonus: 12, Attribute: "In", Notes: "für Muttersprache"},
|
||||
},
|
||||
TypicalSpells: []string{"Wundertaten", "Heilen von Wunden"},
|
||||
},
|
||||
{
|
||||
ClassCode: "PS",
|
||||
ClassName: "Priester Streiter",
|
||||
SpellPoints: 5,
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 3,
|
||||
"Kampf": 2,
|
||||
"Wissen": 2,
|
||||
"Waffen": 8,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Erste Hilfe", Bonus: 8, Attribute: "Gs", Notes: ""},
|
||||
{Name: "Schreiben", Bonus: 12, Attribute: "In", Notes: "für Muttersprache"},
|
||||
},
|
||||
TypicalSpells: []string{"Wundertaten", "Bannen von Finsterwerk", "Strahlender Panzer"},
|
||||
},
|
||||
{
|
||||
ClassCode: "Sc",
|
||||
ClassName: "Schamane",
|
||||
SpellPoints: 5,
|
||||
LearningPoints: map[string]int{
|
||||
"Alltag": 2,
|
||||
"Körper": 4,
|
||||
"Wissen": 2,
|
||||
"Waffen": 6,
|
||||
},
|
||||
TypicalSkills: []struct {
|
||||
Name string
|
||||
Bonus int
|
||||
Attribute string
|
||||
Notes string
|
||||
}{
|
||||
{Name: "Tierkunde", Bonus: 8, Attribute: "In", Notes: ""},
|
||||
{Name: "Überleben", Bonus: 8, Attribute: "In", Notes: "in Heimatlandschaft"},
|
||||
},
|
||||
TypicalSpells: []string{"Dweomer", "Wundertaten", "Austreibung des Bösen", "Bannen von Gift"},
|
||||
},
|
||||
}
|
||||
|
||||
// Process each character class
|
||||
for _, cd := range classData {
|
||||
// Find or create character class
|
||||
var charClass CharacterClass
|
||||
result := database.DB.Where("code = ?", cd.ClassCode).First(&charClass)
|
||||
if result.Error != nil {
|
||||
fmt.Printf("Warning: Character class %s (%s) not found in database, skipping\n", cd.ClassName, cd.ClassCode)
|
||||
continue
|
||||
}
|
||||
|
||||
// Insert learning points for each category
|
||||
for categoryName, points := range cd.LearningPoints {
|
||||
var category SkillCategory
|
||||
if err := database.DB.Where("name = ?", categoryName).First(&category).Error; err != nil {
|
||||
fmt.Printf("Warning: Skill category %s not found, skipping\n", categoryName)
|
||||
continue
|
||||
}
|
||||
|
||||
learningPoints := ClassLearningPoints{
|
||||
CharacterClassID: charClass.ID,
|
||||
SkillCategoryID: category.ID,
|
||||
Points: points,
|
||||
}
|
||||
|
||||
if err := database.DB.Where("character_class_id = ? AND skill_category_id = ?",
|
||||
charClass.ID, category.ID).FirstOrCreate(&learningPoints).Error; err != nil {
|
||||
return fmt.Errorf("failed to insert learning points for %s/%s: %w", cd.ClassName, categoryName, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Insert spell points if applicable
|
||||
if cd.SpellPoints > 0 {
|
||||
spellPoints := ClassSpellPoints{
|
||||
CharacterClassID: charClass.ID,
|
||||
SpellPoints: cd.SpellPoints,
|
||||
}
|
||||
|
||||
if err := database.DB.Where("character_class_id = ?", charClass.ID).
|
||||
FirstOrCreate(&spellPoints).Error; err != nil {
|
||||
return fmt.Errorf("failed to insert spell points for %s: %w", cd.ClassName, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Insert typical skills
|
||||
for _, ts := range cd.TypicalSkills {
|
||||
var skill Skill
|
||||
if err := database.DB.Where("name = ?", ts.Name).First(&skill).Error; err != nil {
|
||||
fmt.Printf("Warning: Skill %s not found for class %s, skipping\n", ts.Name, cd.ClassName)
|
||||
continue
|
||||
}
|
||||
|
||||
typicalSkill := ClassTypicalSkill{
|
||||
CharacterClassID: charClass.ID,
|
||||
SkillID: skill.ID,
|
||||
Bonus: ts.Bonus,
|
||||
Attribute: ts.Attribute,
|
||||
Notes: ts.Notes,
|
||||
}
|
||||
|
||||
if err := database.DB.Where("character_class_id = ? AND skill_id = ?",
|
||||
charClass.ID, skill.ID).FirstOrCreate(&typicalSkill).Error; err != nil {
|
||||
return fmt.Errorf("failed to insert typical skill %s for %s: %w", ts.Name, cd.ClassName, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Insert typical spells
|
||||
for _, spellName := range cd.TypicalSpells {
|
||||
var spell Spell
|
||||
if err := database.DB.Where("name = ?", spellName).First(&spell).Error; err != nil {
|
||||
fmt.Printf("Warning: Spell %s not found for class %s, creating reference with notes\n", spellName, cd.ClassName)
|
||||
// For special cases like "beliebig außer...", we can skip or create a placeholder
|
||||
continue
|
||||
}
|
||||
|
||||
typicalSpell := ClassTypicalSpell{
|
||||
CharacterClassID: charClass.ID,
|
||||
SpellID: spell.ID,
|
||||
Notes: "",
|
||||
}
|
||||
|
||||
if err := database.DB.Where("character_class_id = ? AND spell_id = ?",
|
||||
charClass.ID, spell.ID).FirstOrCreate(&typicalSpell).Error; err != nil {
|
||||
return fmt.Errorf("failed to insert typical spell %s for %s: %w", spellName, cd.ClassName, err)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Populated learning points data for %s (%s)\n", cd.ClassName, cd.ClassCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user