Tabellenstruktur im Code Migrationen im Code
redundanzen entfernt und zusatzinfos (Quelle) integriert
This commit is contained in:
@@ -0,0 +1,447 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"bamort/database"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Source repräsentiert ein Regelwerk/Quellenbuch
|
||||
type Source struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Code string `gorm:"uniqueIndex;size:10;not null" json:"code"` // z.B. "KOD", "ARK", "MYS"
|
||||
Name string `gorm:"unique;not null" json:"name"` // z.B. "Kodex", "Arkanum", "Mysterium"
|
||||
FullName string `json:"full_name,omitempty"` // z.B. "Midgard Regelwerk - Kodex"
|
||||
Edition string `json:"edition,omitempty"` // z.B. "5. Edition"
|
||||
Publisher string `json:"publisher,omitempty"` // z.B. "Pegasus Spiele"
|
||||
PublishYear int `json:"publish_year,omitempty"` // Erscheinungsjahr
|
||||
Description string `json:"description,omitempty"` // Beschreibung des Werks
|
||||
IsCore bool `gorm:"default:false" json:"is_core"` // Ist es ein Grundregelwerk?
|
||||
IsActive bool `gorm:"default:true" json:"is_active"` // Ist das Werk aktiv/verfügbar?
|
||||
GameSystem string `gorm:"index;default:midgard" json:"game_system"`
|
||||
}
|
||||
|
||||
// CharacterClass repräsentiert eine Charakterklasse mit Code und vollständigem Namen
|
||||
type CharacterClass struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Code string `gorm:"uniqueIndex;size:3" json:"code"` // z.B. "Hx", "Ma", "Kr"
|
||||
Name string `gorm:"unique;not null" json:"name"` // z.B. "Hexer", "Magier", "Krieger"
|
||||
Description string `json:"description,omitempty"` // Optional: Beschreibung der Klasse
|
||||
SourceID uint `gorm:"not null;index" json:"source_id"` // Verweis auf das Quellenbuch
|
||||
GameSystem string `gorm:"index;default:midgard" json:"game_system"`
|
||||
Source Source `gorm:"foreignKey:SourceID;constraint:OnUpdate:CASCADE,OnDelete:RESTRICT" json:"source"`
|
||||
}
|
||||
|
||||
// SkillCategory repräsentiert eine Fertigkeitskategorie
|
||||
type SkillCategory struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"unique;not null" json:"name"` // z.B. "Alltag", "Kampf", "Waffen"
|
||||
Description string `json:"description,omitempty"` // Optional: Beschreibung der Kategorie
|
||||
SourceID uint `gorm:"not null;index" json:"source_id"` // Verweis auf das Quellenbuch
|
||||
GameSystem string `gorm:"index;default:midgard" json:"game_system"`
|
||||
Source Source `gorm:"foreignKey:SourceID;constraint:OnUpdate:CASCADE,OnDelete:RESTRICT" json:"source"`
|
||||
}
|
||||
|
||||
// SkillDifficulty repräsentiert Schwierigkeitsgrade
|
||||
type SkillDifficulty struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"unique;not null" json:"name"` // z.B. "leicht", "normal", "schwer", "sehr schwer"
|
||||
Description string `json:"description,omitempty"` // Optional: Beschreibung
|
||||
GameSystem string `gorm:"index;default:midgard" json:"game_system"`
|
||||
}
|
||||
|
||||
// SpellSchool repräsentiert Zauberschulen
|
||||
type SpellSchool struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"unique;not null" json:"name"` // z.B. "Beherrschen", "Bewegen", "Erkennen"
|
||||
Description string `json:"description,omitempty"` // Optional: Beschreibung
|
||||
SourceID uint `gorm:"not null;index" json:"source_id"` // Verweis auf das Quellenbuch
|
||||
GameSystem string `gorm:"index;default:midgard" json:"game_system"`
|
||||
Source Source `gorm:"foreignKey:SourceID;constraint:OnUpdate:CASCADE,OnDelete:RESTRICT" json:"source"`
|
||||
}
|
||||
|
||||
// ClassCategoryEPCost definiert EP-Kosten für 1 Trainingseinheit (TE) pro Charakterklasse und Fertigkeitskategorie
|
||||
type ClassCategoryEPCost struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
CharacterClassID uint `gorm:"not null;index" json:"character_class_id"`
|
||||
SkillCategoryID uint `gorm:"not null;index" json:"skill_category_id"`
|
||||
EPPerTE int `gorm:"not null" json:"ep_per_te"` // EP-Kosten für 1 Trainingseinheit
|
||||
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"`
|
||||
}
|
||||
|
||||
// ClassSpellSchoolEPCost definiert EP-Kosten für 1 Lerneinheit (LE) für Zauber pro Charakterklasse und Zauberschule
|
||||
type ClassSpellSchoolEPCost struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
CharacterClassID uint `gorm:"not null;index" json:"character_class_id"`
|
||||
SpellSchoolID uint `gorm:"not null;index" json:"spell_school_id"`
|
||||
EPPerLE int `gorm:"not null" json:"ep_per_le"` // EP-Kosten für 1 Lerneinheit
|
||||
CharacterClass CharacterClass `gorm:"foreignKey:CharacterClassID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"character_class"`
|
||||
SpellSchool SpellSchool `gorm:"foreignKey:SpellSchoolID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"spell_school"`
|
||||
}
|
||||
|
||||
// SpellLevelLECost definiert LE-Kosten pro Zauber-Stufe
|
||||
type SpellLevelLECost struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Level int `gorm:"uniqueIndex;not null" json:"level"` // Zauber-Stufe (1-12)
|
||||
LERequired int `gorm:"not null" json:"le_required"` // Benötigte Lerneinheiten
|
||||
GameSystem string `gorm:"index;default:midgard" json:"game_system"`
|
||||
}
|
||||
|
||||
// SkillCategoryDifficulty definiert die Schwierigkeit einer Fertigkeit in einer bestimmten Kategorie
|
||||
// Eine Fertigkeit kann in mehreren Kategorien mit unterschiedlichen Schwierigkeiten existieren
|
||||
type SkillCategoryDifficulty struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
SkillID uint `gorm:"not null;index" json:"skill_id"`
|
||||
SkillCategoryID uint `gorm:"not null;index" json:"skill_category_id"`
|
||||
SkillDifficultyID uint `gorm:"not null;index" json:"skill_difficulty_id"`
|
||||
LearnCost int `gorm:"not null" json:"learn_cost"` // LE-Kosten für das Erlernen
|
||||
Skill Skill `gorm:"foreignKey:SkillID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"skill"`
|
||||
SkillCategory SkillCategory `gorm:"foreignKey:SkillCategoryID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"skill_category"`
|
||||
SkillDifficulty SkillDifficulty `gorm:"foreignKey:SkillDifficultyID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"skill_difficulty"`
|
||||
}
|
||||
|
||||
// SkillImprovementCost definiert TE-Kosten für Verbesserungen basierend auf Kategorie, Schwierigkeit und aktuellem Wert
|
||||
type SkillImprovementCost struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
SkillCategoryDifficultyID uint `gorm:"not null;index" json:"skill_category_difficulty_id"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// Für komplexere Queries: View oder Helper-Strukturen
|
||||
|
||||
// SkillLearningInfo kombiniert alle Informationen für eine Fertigkeit in einer bestimmten Kategorie
|
||||
type SkillLearningInfo struct {
|
||||
SkillID uint `json:"skill_id"`
|
||||
SkillName string `json:"skill_name"`
|
||||
CategoryID uint `json:"category_id"`
|
||||
CategoryName string `json:"category_name"`
|
||||
DifficultyID uint `json:"difficulty_id"`
|
||||
DifficultyName string `json:"difficulty_name"`
|
||||
LearnCost int `json:"learn_cost"`
|
||||
CharacterClassID uint `json:"character_class_id"`
|
||||
ClassCode string `json:"class_code"`
|
||||
ClassName string `json:"class_name"`
|
||||
EPPerTE int `json:"ep_per_te"`
|
||||
}
|
||||
|
||||
// SpellLearningInfo kombiniert alle Informationen für einen Zauber
|
||||
type SpellLearningInfo struct {
|
||||
SpellID uint `json:"spell_id"`
|
||||
SpellName string `json:"spell_name"`
|
||||
SpellLevel int `json:"spell_level"`
|
||||
SchoolID uint `json:"school_id"`
|
||||
SchoolName string `json:"school_name"`
|
||||
CharacterClassID uint `json:"character_class_id"`
|
||||
ClassCode string `json:"class_code"`
|
||||
ClassName string `json:"class_name"`
|
||||
EPPerLE int `json:"ep_per_le"`
|
||||
LERequired int `json:"le_required"`
|
||||
}
|
||||
|
||||
// TableName-Methoden für GORM
|
||||
func (Source) TableName() string {
|
||||
return "learning_sources"
|
||||
}
|
||||
|
||||
func (CharacterClass) TableName() string {
|
||||
return "learning_character_classes"
|
||||
}
|
||||
|
||||
func (SkillCategory) TableName() string {
|
||||
return "learning_skill_categories"
|
||||
}
|
||||
|
||||
func (SkillDifficulty) TableName() string {
|
||||
return "learning_skill_difficulties"
|
||||
}
|
||||
|
||||
func (SpellSchool) TableName() string {
|
||||
return "learning_spell_schools"
|
||||
}
|
||||
|
||||
func (ClassCategoryEPCost) TableName() string {
|
||||
return "learning_class_category_ep_costs"
|
||||
}
|
||||
|
||||
func (ClassSpellSchoolEPCost) TableName() string {
|
||||
return "learning_class_spell_school_ep_costs"
|
||||
}
|
||||
|
||||
func (SpellLevelLECost) TableName() string {
|
||||
return "learning_spell_level_le_costs"
|
||||
}
|
||||
|
||||
func (SkillCategoryDifficulty) TableName() string {
|
||||
return "learning_skill_category_difficulties"
|
||||
}
|
||||
|
||||
func (SkillImprovementCost) TableName() string {
|
||||
return "learning_skill_improvement_costs"
|
||||
}
|
||||
|
||||
// CRUD-Methoden
|
||||
|
||||
func (s *Source) Create() error {
|
||||
return database.DB.Create(s).Error
|
||||
}
|
||||
|
||||
func (s *Source) FirstByCode(code string) error {
|
||||
return database.DB.Where("code = ?", code).First(s).Error
|
||||
}
|
||||
|
||||
func (s *Source) FirstByName(name string) error {
|
||||
return database.DB.Where("name = ?", name).First(s).Error
|
||||
}
|
||||
|
||||
func (cc *CharacterClass) Create() error {
|
||||
return database.DB.Create(cc).Error
|
||||
}
|
||||
|
||||
func (cc *CharacterClass) FirstByCode(code string) error {
|
||||
return database.DB.Where("code = ?", code).First(cc).Error
|
||||
}
|
||||
|
||||
func (sc *SkillCategory) Create() error {
|
||||
return database.DB.Create(sc).Error
|
||||
}
|
||||
|
||||
func (sc *SkillCategory) FirstByName(name string) error {
|
||||
return database.DB.Where("name = ?", name).First(sc).Error
|
||||
}
|
||||
|
||||
func (sd *SkillDifficulty) Create() error {
|
||||
return database.DB.Create(sd).Error
|
||||
}
|
||||
|
||||
func (sd *SkillDifficulty) FirstByName(name string) error {
|
||||
return database.DB.Where("name = ?", name).First(sd).Error
|
||||
}
|
||||
|
||||
func (ss *SpellSchool) Create() error {
|
||||
return database.DB.Create(ss).Error
|
||||
}
|
||||
|
||||
func (ss *SpellSchool) FirstByName(name string) error {
|
||||
return database.DB.Where("name = ?", name).First(ss).Error
|
||||
}
|
||||
|
||||
func (ccec *ClassCategoryEPCost) Create() error {
|
||||
return database.DB.Create(ccec).Error
|
||||
}
|
||||
|
||||
func (cssec *ClassSpellSchoolEPCost) Create() error {
|
||||
return database.DB.Create(cssec).Error
|
||||
}
|
||||
|
||||
func (sllc *SpellLevelLECost) Create() error {
|
||||
return database.DB.Create(sllc).Error
|
||||
}
|
||||
|
||||
func (scd *SkillCategoryDifficulty) Create() error {
|
||||
return database.DB.Create(scd).Error
|
||||
}
|
||||
|
||||
func (sic *SkillImprovementCost) Create() error {
|
||||
return database.DB.Create(sic).Error
|
||||
}
|
||||
|
||||
// Komplexere Query-Methoden
|
||||
|
||||
// GetEPPerTEForClassAndCategory holt die EP-Kosten für eine Klasse und Kategorie
|
||||
func GetEPPerTEForClassAndCategory(classCode string, categoryName string) (int, error) {
|
||||
var result ClassCategoryEPCost
|
||||
err := database.DB.
|
||||
Joins("JOIN learning_character_classes ON learning_character_classes.id = learning_class_category_ep_costs.character_class_id").
|
||||
Joins("JOIN learning_skill_categories ON learning_skill_categories.id = learning_class_category_ep_costs.skill_category_id").
|
||||
Where("learning_character_classes.code = ? AND learning_skill_categories.name = ?", classCode, categoryName).
|
||||
First(&result).Error
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.EPPerTE, nil
|
||||
}
|
||||
|
||||
// GetEPPerLEForClassAndSpellSchool holt die EP-Kosten für eine Klasse und Zauberschule
|
||||
func GetEPPerLEForClassAndSpellSchool(classCode string, schoolName string) (int, error) {
|
||||
var result ClassSpellSchoolEPCost
|
||||
err := database.DB.
|
||||
Joins("JOIN learning_character_classes ON learning_character_classes.id = learning_class_spell_school_ep_costs.character_class_id").
|
||||
Joins("JOIN learning_spell_schools ON learning_spell_schools.id = learning_class_spell_school_ep_costs.spell_school_id").
|
||||
Where("learning_character_classes.code = ? AND learning_spell_schools.name = ?", classCode, schoolName).
|
||||
First(&result).Error
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.EPPerLE, nil
|
||||
}
|
||||
|
||||
// GetSkillCategoryAndDifficulty findet die beste Kategorie für eine Fertigkeit basierend auf niedrigsten EP-Kosten
|
||||
func GetSkillCategoryAndDifficulty(skillName string, classCode string) (*SkillLearningInfo, error) {
|
||||
var results []SkillLearningInfo
|
||||
|
||||
err := database.DB.Raw(`
|
||||
SELECT
|
||||
s.id as skill_id,
|
||||
s.name as skill_name,
|
||||
sc.id as category_id,
|
||||
sc.name as category_name,
|
||||
sd.id as difficulty_id,
|
||||
sd.name as difficulty_name,
|
||||
scd.learn_cost,
|
||||
cc.id as character_class_id,
|
||||
cc.code as class_code,
|
||||
cc.name as class_name,
|
||||
ccec.ep_per_te
|
||||
FROM lookup_lists s
|
||||
JOIN learning_skill_category_difficulties scd ON s.id = scd.skill_id
|
||||
JOIN learning_skill_categories sc ON scd.skill_category_id = sc.id
|
||||
JOIN learning_skill_difficulties sd ON scd.skill_difficulty_id = sd.id
|
||||
JOIN learning_class_category_ep_costs ccec ON sc.id = ccec.skill_category_id
|
||||
JOIN learning_character_classes cc ON ccec.character_class_id = cc.id
|
||||
WHERE s.name = ? AND cc.code = ?
|
||||
ORDER BY (scd.learn_cost * 3 * ccec.ep_per_te) ASC
|
||||
`, skillName, classCode).Scan(&results).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(results) == 0 {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
|
||||
return &results[0], nil
|
||||
}
|
||||
|
||||
// GetSpellLearningInfo holt alle Informationen für das Erlernen eines Zaubers
|
||||
func GetSpellLearningInfo(spellName string, classCode string) (*SpellLearningInfo, error) {
|
||||
var result SpellLearningInfo
|
||||
|
||||
err := database.DB.Raw(`
|
||||
SELECT
|
||||
s.id as spell_id,
|
||||
s.name as spell_name,
|
||||
s.stufe as spell_level,
|
||||
ss.id as school_id,
|
||||
ss.name as school_name,
|
||||
cc.id as character_class_id,
|
||||
cc.code as class_code,
|
||||
cc.name as class_name,
|
||||
cssec.ep_per_le,
|
||||
sllc.le_required
|
||||
FROM lookup_lists s
|
||||
JOIN learning_spell_schools ss ON s.category = ss.name
|
||||
JOIN learning_class_spell_school_ep_costs cssec ON ss.id = cssec.spell_school_id
|
||||
JOIN learning_character_classes cc ON cssec.character_class_id = cc.id
|
||||
JOIN learning_spell_level_le_costs sllc ON s.stufe = sllc.level
|
||||
WHERE s.name = ? AND cc.code = ?
|
||||
`, spellName, classCode).Scan(&result).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// GetImprovementCost holt die Verbesserungskosten für eine Fertigkeit
|
||||
func GetImprovementCost(skillName string, categoryName string, difficultyName string, currentLevel int) (int, error) {
|
||||
var result SkillImprovementCost
|
||||
|
||||
err := database.DB.
|
||||
Joins("JOIN learning_skill_category_difficulties scd ON learning_skill_improvement_costs.skill_category_difficulty_id = scd.id").
|
||||
Joins("JOIN lookup_lists s ON scd.skill_id = s.id").
|
||||
Joins("JOIN learning_skill_categories sc ON scd.skill_category_id = sc.id").
|
||||
Joins("JOIN learning_skill_difficulties sd ON scd.skill_difficulty_id = sd.id").
|
||||
Where("s.name = ? AND sc.name = ? AND sd.name = ? AND learning_skill_improvement_costs.current_level = ?",
|
||||
skillName, categoryName, difficultyName, currentLevel).
|
||||
First(&result).Error
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return result.TERequired, nil
|
||||
}
|
||||
|
||||
// Quellenmanagement-Funktionen
|
||||
|
||||
// GetActiveSourceCodes gibt alle aktiven Quellencodes zurück
|
||||
func GetActiveSourceCodes() ([]string, error) {
|
||||
var codes []string
|
||||
err := database.DB.Model(&Source{}).Where("is_active = ?", true).Pluck("code", &codes).Error
|
||||
return codes, err
|
||||
}
|
||||
|
||||
// GetSourcesByGameSystem gibt alle Quellen für ein bestimmtes Spielsystem zurück
|
||||
func GetSourcesByGameSystem(gameSystem string) ([]Source, error) {
|
||||
var sources []Source
|
||||
err := database.DB.Where("game_system = ?", gameSystem).Order("is_core DESC, code ASC").Find(&sources).Error
|
||||
return sources, err
|
||||
}
|
||||
|
||||
// GetSkillsByActiveSources gibt alle Fertigkeiten zurück, die in aktiven Quellen definiert sind
|
||||
func GetSkillsByActiveSources(gameSystem string) ([]Skill, error) {
|
||||
var skills []Skill
|
||||
err := database.DB.
|
||||
Joins("LEFT JOIN learning_sources ON lookup_lists.source_id = learning_sources.id").
|
||||
Where("lookup_lists.game_system = ? AND (learning_sources.is_active = ? OR lookup_lists.source_id IS NULL)", gameSystem, true).
|
||||
Find(&skills).Error
|
||||
return skills, err
|
||||
}
|
||||
|
||||
// GetSpellsByActiveSources gibt alle Zauber zurück, die in aktiven Quellen definiert sind
|
||||
func GetSpellsByActiveSources(gameSystem string) ([]Spell, error) {
|
||||
var spells []Spell
|
||||
err := database.DB.
|
||||
Joins("LEFT JOIN learning_sources ON lookup_lists.source_id = learning_sources.id").
|
||||
Where("lookup_lists.game_system = ? AND (learning_sources.is_active = ? OR lookup_lists.source_id IS NULL)", gameSystem, true).
|
||||
Find(&spells).Error
|
||||
return spells, err
|
||||
}
|
||||
|
||||
// GetCharacterClassesByActiveSources gibt alle Charakterklassen zurück, die in aktiven Quellen definiert sind
|
||||
func GetCharacterClassesByActiveSources(gameSystem string) ([]CharacterClass, error) {
|
||||
var classes []CharacterClass
|
||||
err := database.DB.
|
||||
Joins("LEFT JOIN learning_sources ON learning_character_classes.source_id = learning_sources.id").
|
||||
Where("learning_character_classes.game_system = ? AND (learning_sources.is_active = ? OR learning_character_classes.source_id IS NULL)", gameSystem, true).
|
||||
Find(&classes).Error
|
||||
return classes, err
|
||||
}
|
||||
|
||||
// SetSourceActive aktiviert oder deaktiviert eine Quelle
|
||||
func SetSourceActive(sourceCode string, active bool) error {
|
||||
return database.DB.Model(&Source{}).Where("code = ?", sourceCode).Update("is_active", active).Error
|
||||
}
|
||||
|
||||
// GetDefaultSourceForContentType gibt die Standardquelle für einen Inhaltstyp zurück
|
||||
func GetDefaultSourceForContentType(contentType string) (string, error) {
|
||||
switch contentType {
|
||||
case "skill", "character_class", "skill_category":
|
||||
return "KOD", nil
|
||||
case "spell", "spell_school":
|
||||
return "ARK", nil
|
||||
case "unknown":
|
||||
return "UNB", nil
|
||||
default:
|
||||
return "KOD", nil // Fallback auf Kodex
|
||||
}
|
||||
}
|
||||
|
||||
// GetContentTypeDefaultSources gibt eine Übersicht aller Standardquellen-Zuordnungen zurück
|
||||
func GetContentTypeDefaultSources() map[string]string {
|
||||
return map[string]string{
|
||||
"character_class": "KOD", // Charakterklassen -> Kodex
|
||||
"skill": "KOD", // Fertigkeiten -> Kodex
|
||||
"skill_category": "KOD", // Fertigkeitskategorien -> Kodex
|
||||
"spell": "ARK", // Zauber -> Arkanum
|
||||
"spell_school": "ARK", // Zauberschulen -> Arkanum (erweiterte), KOD (Basis)
|
||||
"unknown": "UNB", // Unbekannte Inhalte -> Unbekannt
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user