2025-07-24 07:39:43 +02:00
package character
import (
"bamort/gsmaster"
2025-07-27 23:13:04 +02:00
"bamort/models"
2025-07-24 07:39:43 +02:00
"fmt"
"net/http"
"strconv"
"strings"
"github.com/gin-gonic/gin"
)
type SkillCostRequest struct {
Name string ` json:"name" binding:"required" ` // Name der Fertigkeit
CurrentLevel int ` json:"current_level,omitempty" ` // Aktueller Wert (nur für Verbesserung)
Type string ` json:"type" binding:"required,oneof=skill spell weapon" ` // 'skill', 'spell' oder 'weapon'
Action string ` json:"action" binding:"required,oneof=learn improve" ` // 'learn' oder 'improve'
TargetLevel int ` json:"target_level,omitempty" ` // Zielwert (optional, für Kostenberechnung bis zu einem bestimmten Level)
UsePP int ` json:"use_pp,omitempty" ` // Anzahl der zu verwendenden Praxispunkte
// Belohnungsoptionen
Reward * RewardOptions ` json:"reward,omitempty" ` // Belohnungsoptionen
}
// RewardOptions definiert die verschiedenen Belohnungsmöglichkeiten
type RewardOptions struct {
Type string ` json:"type,omitempty" binding:"omitempty,oneof=free_learning free_spell_learning half_ep_improvement gold_for_ep" ` // Art der Belohnung
UseGoldForEP bool ` json:"use_gold_for_ep,omitempty" ` // 10 GS statt 1 EP verwenden
MaxGoldEP int ` json:"max_gold_ep,omitempty" ` // Maximale EP die durch Gold ersetzt werden (automatisch: Hälfte der Kosten)
}
type SkillCostResponse struct {
2025-07-27 23:31:04 +02:00
* models . LearnCost
2025-07-24 07:39:43 +02:00
SkillName string ` json:"skill_name" `
SkillType string ` json:"skill_type" `
Action string ` json:"action" `
CharacterID uint ` json:"character_id" `
CurrentLevel int ` json:"current_level,omitempty" `
TargetLevel int ` json:"target_level,omitempty" `
Category string ` json:"category,omitempty" `
Difficulty string ` json:"difficulty,omitempty" `
CanAfford bool ` json:"can_afford" `
Notes string ` json:"notes,omitempty" `
PPUsed int ` json:"pp_used,omitempty" ` // Anzahl der verwendeten Praxispunkte
PPAvailable int ` json:"pp_available,omitempty" ` // Verfügbare Praxispunkte für diese Kategorie
// Belohnungsdetails
2025-07-27 23:31:04 +02:00
RewardApplied string ` json:"reward_applied,omitempty" ` // Art der angewendeten Belohnung
OriginalCostStruct * models . LearnCost ` json:"original_cost_struct,omitempty" ` // Ursprüngliche Kosten ohne Belohnung
Savings * models . LearnCost ` json:"savings,omitempty" ` // Ersparnisse durch Belohnung
GoldUsedForEP int ` json:"gold_used_for_ep,omitempty" ` // Gold das für EP verwendet wurde
PPReduction int ` json:"pp_reduction,omitempty" ` // Reduktion der Kosten durch PP
OriginalCost int ` json:"original_cost,omitempty" ` // Ursprüngliche Kosten (vor PP-Reduktion)
FinalCost int ` json:"final_cost,omitempty" ` // Endgültige Kosten (nach PP-Reduktion)
2025-07-24 07:39:43 +02:00
}
type MultiLevelCostResponse struct {
SkillName string ` json:"skill_name" `
SkillType string ` json:"skill_type" `
CharacterID uint ` json:"character_id" `
CurrentLevel int ` json:"current_level" `
TargetLevel int ` json:"target_level" `
LevelCosts [ ] SkillCostResponse ` json:"level_costs" `
2025-07-27 23:31:04 +02:00
TotalCost * models . LearnCost ` json:"total_cost" `
2025-07-24 07:39:43 +02:00
CanAffordTotal bool ` json:"can_afford_total" `
}
2025-07-29 23:29:12 +02:00
// GetLernCostNewSystem verwendet das neue Datenbank-Lernkosten-System
// und produziert die gleichen Ergebnisse wie GetLernCost.
//
2026-01-30 15:17:33 +01:00
// Wie es funktionert:
// - Für "learn" Aktion: Nur eine Berechnung, da Lernkosten einmalig sind
// - Für "improve" Aktion: Berechne für jedes Level von current+1 bis 18
// - Berücksichtigt Praxispunkte (PP) und Gold-für-EP Konvertierung
// - Wendet Belohnungen an (kostenloses Lernen, halbe EP, etc.)
// - Gibt eine Liste von Kosten pro Level zurück
// Schritt für Schritt:
// 1. Hole Charakter und Klassenabkürzung
// 2. Normalisiere Fertigkeits-/Zaubername
// 3. Initialisiere einzusetzende/verbleibende PP und Gold
// 4. Je nach Aktion:
// 4.1 "learn": Hole Lerninformationen und berechne Kosten
// 4.1.1 "spell": Hole Zauber-Lerninformationen und berechne Kosten
// 4.1.2 "skill": Hole Fertigkeits-Lerninformationen und berechne Kosten
// 4.2 "improve": Für jedes Level, hole Verbesserungsinformationen und berechne Kosten
// (nur Fertigkeiten, keine Zauber)
2025-07-29 23:29:12 +02:00
//
2026-01-30 15:17:33 +01:00
// 5. Wende Belohnungen an
// 6. Wende PP und Gold-für-EP an
// 7. Sammle Ergebnisse und sende als JSON-Antwort
2025-07-29 23:29:12 +02:00
func GetLernCostNewSystem ( c * gin . Context ) {
// Request-Parameter abrufen
var request gsmaster . LernCostRequest
if err := c . ShouldBindJSON ( & request ) ; err != nil {
respondWithError ( c , http . StatusBadRequest , "Ungültige Anfrageparameter: " + err . Error ( ) )
return
}
2026-01-30 15:17:33 +01:00
// 1. Hole Charakter
2025-07-29 23:29:12 +02:00
charID := fmt . Sprintf ( "%d" , request . CharId )
var character models . Char
if err := character . FirstID ( charID ) ; err != nil {
respondWithError ( c , http . StatusNotFound , "Charakter nicht gefunden" )
return
}
// Verwende Klassenabkürzung wenn der Typ länger als 3 Zeichen ist
var characterClass string
if len ( character . Typ ) > 3 {
2025-08-01 07:19:02 +02:00
characterClass = gsmaster . GetClassAbbreviationNewSystem ( character . Typ )
2025-07-29 23:29:12 +02:00
} else {
characterClass = character . Typ
}
2026-01-30 15:17:33 +01:00
//2. Normalize skill/spell name (trim whitespace, proper case)
2025-07-29 23:29:12 +02:00
skillName := strings . TrimSpace ( request . Name )
var response [ ] gsmaster . SkillCostResultNew
remainingPP := request . UsePP
remainingGold := request . UseGold
2025-07-30 11:09:21 +02:00
// Für "learn" Aktion: nur eine Berechnung, da Lernkosten einmalig sind
if request . Action == "learn" {
2026-01-30 15:17:33 +01:00
// 4.1 "learn": Hole Lerninformationen und berechne Kosten
2025-07-30 13:23:35 +02:00
if request . Type == "spell" {
2026-01-30 15:17:33 +01:00
// 4.1.1 "spell": Hole Zauber-Lerninformationen und berechne Kosten
2025-07-30 13:23:35 +02:00
// Spell learning logic
2025-07-31 22:49:46 +02:00
spellInfo , err := models . GetSpellLearningInfoNewSystem ( skillName , characterClass )
2025-07-30 13:23:35 +02:00
if err != nil {
respondWithError ( c , http . StatusBadRequest , fmt . Sprintf ( "Zauber '%s' nicht gefunden oder nicht für Klasse '%s' verfügbar: %v" , skillName , characterClass , err ) )
return
}
levelResult := gsmaster . SkillCostResultNew {
CharacterID : charID ,
CharacterClass : characterClass ,
SkillName : skillName ,
Category : spellInfo . SchoolName ,
Difficulty : fmt . Sprintf ( "Stufe %d" , spellInfo . SpellLevel ) ,
TargetLevel : 1 , // Lernkosten sind für das Erlernen des Zaubers (Level 1)
}
err = calculateSpellLearnCostNewSystem ( & request , & levelResult , & remainingPP , & remainingGold , spellInfo )
if err != nil {
respondWithError ( c , http . StatusBadRequest , "Fehler bei der Kostenberechnung: " + err . Error ( ) )
return
}
response = append ( response , levelResult )
} else {
2026-01-30 15:17:33 +01:00
// 4.1.2 "skill": Hole Fertigkeits-Lerninformationen und berechne Kosten
2025-08-01 07:19:02 +02:00
skillInfo , err := models . GetSkillCategoryAndDifficultyNewSystem ( skillName , characterClass )
2025-07-30 13:23:35 +02:00
if err != nil {
respondWithError ( c , http . StatusBadRequest , fmt . Sprintf ( "Fertigkeit '%s' nicht gefunden oder nicht für Klasse '%s' verfügbar: %v" , skillName , characterClass , err ) )
return
}
2025-07-29 23:29:12 +02:00
2025-07-30 13:23:35 +02:00
levelResult := gsmaster . SkillCostResultNew {
CharacterID : charID ,
CharacterClass : characterClass ,
SkillName : skillName ,
Category : skillInfo . CategoryName ,
Difficulty : skillInfo . DifficultyName ,
TargetLevel : 1 , // Lernkosten sind für das Erlernen der Fertigkeit (Level 1)
}
err = calculateSkillLearnCostNewSystem ( & request , & levelResult , & remainingPP , & remainingGold , skillInfo )
if err != nil {
respondWithError ( c , http . StatusBadRequest , "Fehler bei der Kostenberechnung: " + err . Error ( ) )
return
}
response = append ( response , levelResult )
}
} else {
// Für "improve" Aktion: berechne für jedes Level von current+1 bis 18
// Improvement only works on skills, not spells
2025-08-01 07:19:02 +02:00
skillInfo , err := models . GetSkillCategoryAndDifficultyNewSystem ( skillName , characterClass )
2025-07-29 23:29:12 +02:00
if err != nil {
2025-07-30 13:23:35 +02:00
respondWithError ( c , http . StatusBadRequest , fmt . Sprintf ( "Fertigkeit '%s' nicht gefunden oder nicht für Klasse '%s' verfügbar: %v" , skillName , characterClass , err ) )
2025-07-29 23:29:12 +02:00
return
}
2025-07-30 11:09:21 +02:00
for i := request . CurrentLevel + 1 ; i <= 18 ; i ++ {
levelResult := gsmaster . SkillCostResultNew {
CharacterID : charID ,
CharacterClass : characterClass ,
SkillName : skillName ,
Category : skillInfo . CategoryName ,
Difficulty : skillInfo . DifficultyName ,
TargetLevel : i ,
}
2025-08-02 07:15:27 +02:00
err := CalculateSkillImproveCostNewSystem ( & request , & levelResult , i , & remainingPP , & remainingGold , skillInfo )
2025-07-30 11:09:21 +02:00
if err != nil {
respondWithError ( c , http . StatusBadRequest , "Fehler bei der Kostenberechnung: " + err . Error ( ) )
return
}
2025-07-30 13:23:35 +02:00
// für die nächste Runde die PP und Gold reduzieren die zum Lernen genutzt werden sollen
if levelResult . PPUsed > 0 {
request . UsePP -= levelResult . PPUsed
// Sicherstellen, dass PP nicht unter 0 fallen
if request . UsePP < 0 {
request . UsePP = 0
}
}
if levelResult . GoldUsed > 0 {
request . UseGold -= levelResult . GoldUsed
// Sicherstellen, dass Gold nicht unter 0 fällt
if request . UseGold < 0 {
request . UseGold = 0
}
}
2025-07-30 11:09:21 +02:00
response = append ( response , levelResult )
}
2025-07-29 23:29:12 +02:00
}
c . JSON ( http . StatusOK , response )
}
// calculateCostNewSystem berechnet die Kosten für ein Level mit dem neuen Datenbank-System
2025-08-02 07:15:27 +02:00
func CalculateSkillImproveCostNewSystem ( request * gsmaster . LernCostRequest , result * gsmaster . SkillCostResultNew , targetLevel int , remainingPP * int , remainingGold * int , skillInfo * models . SkillLearningInfo ) error {
2025-07-29 23:29:12 +02:00
// 1. Hole die TE-Kosten für die Verbesserung vom aktuellen Level
teRequired , err := models . GetImprovementCost ( skillInfo . SkillName , skillInfo . CategoryName , skillInfo . DifficultyName , targetLevel )
if err != nil {
2025-07-30 14:28:18 +02:00
return fmt . Errorf ( "verbesserungskosten nicht gefunden für %s (Level %d): %v" , skillInfo . SkillName , targetLevel , err )
2025-07-29 23:29:12 +02:00
}
// 2. Hole die EP-Kosten pro TE für diese Klasse und Kategorie
2025-08-02 07:15:27 +02:00
if skillInfo . EPPerTE == 0 {
epPerTE , err := models . GetEPPerTEForClassAndCategory ( result . CharacterClass , skillInfo . CategoryName )
if err != nil {
return fmt . Errorf ( "EP-Kosten pro TE nicht gefunden für Klasse %s, Kategorie %s: %v" , result . CharacterClass , skillInfo . CategoryName , err )
}
skillInfo . EPPerTE = epPerTE
2025-07-29 23:29:12 +02:00
}
2025-07-30 11:09:21 +02:00
// 3. Setze die ursprünglichen TE-Kosten
trainCost := teRequired
2025-07-29 23:29:12 +02:00
2025-07-30 11:09:21 +02:00
// 4. Anwenden von Praxispunkten (PP) - Exakt wie im alten System
2025-07-29 23:29:12 +02:00
ppUsed := 0
if * remainingPP > 0 {
2025-07-30 11:09:21 +02:00
if trainCost < * remainingPP {
ppUsed = trainCost // Maximal so viele PP verwenden wie TE benötigt werden
trainCost = 0 // Wenn PP alle TE abdecken, setze trainCost auf 0
} else if * remainingPP > 0 {
ppUsed = * remainingPP // Verwende alle verfügbaren PP
trainCost -= ppUsed // Reduziere TE um verwendete PP
2025-07-29 23:29:12 +02:00
}
result . PPUsed = ppUsed
* remainingPP -= ppUsed
if * remainingPP < 0 {
* remainingPP = 0
}
}
2025-07-30 11:09:21 +02:00
// 5. Berechne Kosten nach PP-Anwendung (wie im alten System)
result . LE = trainCost
2025-08-02 07:15:27 +02:00
result . EP = skillInfo . EPPerTE * trainCost
2025-07-30 11:09:21 +02:00
result . GoldCost = trainCost * 20 // Wie im alten System: 20 Gold pro TE
// 6. Anwenden von Belohnungen
2025-07-29 23:29:12 +02:00
if request . Reward != nil {
2025-07-30 11:09:21 +02:00
applyRewardNewSystem ( result , request . Reward , result . EP )
2025-07-29 23:29:12 +02:00
}
2025-07-30 11:09:21 +02:00
// 7. Anwenden von Gold für EP (falls verfügbar) - Beschränkt auf EP/2
2025-07-29 23:29:12 +02:00
goldUsed := 0
2025-07-30 11:09:21 +02:00
if * remainingGold > 0 {
// 10 Gold = 1 EP, aber maximal EP/2 kann durch Gold ersetzt werden
2025-07-29 23:29:12 +02:00
maxEPFromGold := result . EP / 2
2025-07-30 11:09:21 +02:00
epFromGold := * remainingGold / 10
2025-07-30 11:10:30 +02:00
2025-07-30 11:09:21 +02:00
if epFromGold > maxEPFromGold {
// Beschränke auf maximal EP/2
epFromGold = maxEPFromGold
goldUsed = epFromGold * 10
} else {
// Verwende das verfügbare Gold
2025-07-29 23:29:12 +02:00
goldUsed = * remainingGold
}
2025-07-30 11:10:30 +02:00
2025-07-30 11:09:21 +02:00
// Reduziere EP um die durch Gold ersetzte Menge
2025-07-29 23:29:12 +02:00
result . EP -= epFromGold
result . GoldUsed = goldUsed
* remainingGold -= goldUsed
if * remainingGold < 0 {
* remainingGold = 0
}
}
2025-07-30 11:09:21 +02:00
return nil
}
2025-07-30 13:23:35 +02:00
// calculateSkillLearnCostNewSystem berechnet die Kosten für das Erlernen einer Fertigkeit (Action: "learn", Type: "skill")
2025-07-30 11:09:21 +02:00
func calculateSkillLearnCostNewSystem ( request * gsmaster . LernCostRequest , result * gsmaster . SkillCostResultNew , remainingPP * int , remainingGold * int , skillInfo * models . SkillLearningInfo ) error {
// 1. Hole die EP-Kosten pro TE für diese Klasse und Kategorie
epPerTE , err := models . GetEPPerTEForClassAndCategory ( result . CharacterClass , skillInfo . CategoryName )
if err != nil {
return fmt . Errorf ( "EP-Kosten pro TE nicht gefunden für Klasse %s, Kategorie %s: %v" , result . CharacterClass , skillInfo . CategoryName , err )
}
// 2. Verwende die Lernkosten (LE) direkt aus der skillInfo - diese enthält bereits alle benötigten Informationen
learnCost := skillInfo . LearnCost
// 3. Berechne Kosten nach Lernregeln (wie im alten System)
result . LE = learnCost
result . EP = epPerTE * result . LE * 3 // Faktor 3 beim Lernen!
result . GoldCost = result . LE * 200 // 200 Gold pro LE (nicht 20 Gold pro TE)
// 4. Anwenden von Belohnungen
if request . Reward != nil {
applyRewardNewSystem ( result , request . Reward , result . EP )
}
2025-07-30 13:23:35 +02:00
// 5. Für Skill-Lernen: Keine PP oder Gold-für-EP Anwendung erlaubt (im Gegensatz zu Spell-Lernen)
// PP und Gold bleiben unverändert, da sie bei Skill-Lernen nicht verwendet werden
2025-07-30 11:09:21 +02:00
2025-07-30 13:23:35 +02:00
return nil
}
2025-07-30 11:09:21 +02:00
2025-07-30 13:23:35 +02:00
// applyRewardNewSystem wendet Belohnungen auf die Kosten an (neues System)
func applyRewardNewSystem ( result * gsmaster . SkillCostResultNew , reward * string , originalEP int ) {
if reward == nil || * reward == "" {
return
}
2025-07-30 11:09:21 +02:00
2025-07-30 13:23:35 +02:00
switch * reward {
case "noGold" :
// Kostenlose Fertigkeiten: Nur Geld ist 0, EP bleiben
result . GoldCost = 0
case "halveep" :
// Halbe EP für Verbesserungen
result . EP = result . EP / 2
case "halveepnoGold" :
// Halbe EP und kein Gold
result . EP = result . EP / 2
result . GoldCost = 0
case "default" :
// Keine Änderungen
break
default :
// Unbekannte Belohnung - ignorieren
break
}
}
// calculateSpellLearnCostNewSystem berechnet die Kosten für das Erlernen eines Zaubers (Action: "learn", Type: "spell")
func calculateSpellLearnCostNewSystem ( request * gsmaster . LernCostRequest , result * gsmaster . SkillCostResultNew , remainingPP * int , remainingGold * int , spellInfo * models . SpellLearningInfo ) error {
// 1. Setze die grundlegenden Zauber-Informationen
result . Category = spellInfo . SchoolName
result . Difficulty = fmt . Sprintf ( "Stufe %d" , spellInfo . SpellLevel )
// 2. Berechne die LE-Kosten basierend auf der Zaubergrad
leRequired := spellInfo . LERequired
// 3. Anwenden von PP (Practice Points): 1 PP = 1 LE Reduktion (bei Zauber-Lernen erlaubt)
ppUsed := 0
if * remainingPP > 0 {
if leRequired <= * remainingPP {
ppUsed = leRequired // Maximal so viele PP verwenden wie LE benötigt werden
leRequired = 0 // Wenn PP alle LE abdecken
} else {
ppUsed = * remainingPP // Verwende alle verfügbaren PP
leRequired -= ppUsed // Reduziere LE um verwendete PP
2025-07-30 11:09:21 +02:00
}
2025-07-30 13:23:35 +02:00
result . PPUsed = ppUsed
* remainingPP -= ppUsed
2025-07-30 11:10:30 +02:00
2025-07-30 13:23:35 +02:00
if * remainingPP < 0 {
* remainingPP = 0
}
}
2025-07-30 11:09:21 +02:00
2025-07-30 13:23:35 +02:00
// 4. Setze die finalen LE-Kosten
result . LE = leRequired
// 5. Berechne EP-Kosten basierend auf LE und EP-pro-LE für diese Klasse/Schule
result . EP = result . LE * spellInfo . EPPerLE
// 6. Berechne Gold-Kosten (Beispiel: 100 Gold pro LE wie im alten System)
result . GoldCost = result . LE * 100
// 7. Anwenden von Belohnungen (spruchrolle, halveep, etc.)
if request . Reward != nil {
applySpellRewardNewSystem ( result , request . Reward )
}
// 8. Gold-für-EP Konvertierung für Zauber-Lernen (erlaubt)
goldUsed := 0
if * remainingGold > 0 {
// 10 Gold = 1 EP, aber maximal EP/2 kann durch Gold ersetzt werden
maxEPFromGold := result . EP / 2
epFromGold := * remainingGold / 10
if epFromGold > maxEPFromGold {
// Beschränke auf maximal EP/2
epFromGold = maxEPFromGold
goldUsed = epFromGold * 10
} else {
// Verwende das verfügbare Gold
goldUsed = * remainingGold
}
// Reduziere EP um die durch Gold ersetzte Menge
result . EP -= epFromGold
result . GoldUsed = goldUsed
* remainingGold -= goldUsed
if * remainingGold < 0 {
* remainingGold = 0
2025-07-30 11:09:21 +02:00
}
2025-07-29 23:29:12 +02:00
}
return nil
}
2025-07-30 13:23:35 +02:00
// applySpellRewardNewSystem wendet zauber-spezifische Belohnungen an
func applySpellRewardNewSystem ( result * gsmaster . SkillCostResultNew , reward * string ) {
2025-07-29 23:29:12 +02:00
if reward == nil || * reward == "" {
return
}
switch * reward {
2025-07-30 13:23:35 +02:00
case "spruchrolle" :
// Spruchrolle: 20 Gold für jeden Versuch und 1/3 EP-Kosten bei Erfolg
result . GoldCost = 20
result . EP = result . EP / 3
2025-07-29 23:29:12 +02:00
case "halveep" :
2025-07-30 13:23:35 +02:00
// Halbe EP für Zauber-Lernen
2025-07-29 23:29:12 +02:00
result . EP = result . EP / 2
case "halveepnoGold" :
// Halbe EP und kein Gold
result . EP = result . EP / 2
result . GoldCost = 0
2025-07-30 13:23:35 +02:00
case "noGold" :
// Nur Geld ist 0, EP bleiben
result . GoldCost = 0
2025-07-29 23:29:12 +02:00
case "default" :
// Keine Änderungen
break
default :
// Unbekannte Belohnung - ignorieren
break
}
}
2025-07-24 07:39:43 +02:00
// Helper function to get current skill level from character
2025-07-28 21:35:29 +02:00
func getCurrentSkillLevel ( character * models . Char , skillName , skillType string ) int {
2025-07-24 07:39:43 +02:00
switch skillType {
case "skill" :
for _ , skill := range character . Fertigkeiten {
if skill . Name == skillName {
return skill . Fertigkeitswert
}
}
case "weapon" :
for _ , skill := range character . Waffenfertigkeiten {
if skill . Name == skillName {
return skill . Fertigkeitswert
}
}
case "spell" :
// Spells don't have levels in the same way
return 0
}
return - 1
}
// applyReward wendet Belohnungen auf die Kosten an
2025-07-27 23:31:04 +02:00
func applyReward ( cost * models . LearnCost , request * SkillCostRequest ) * models . LearnCost {
2025-07-24 07:39:43 +02:00
if request . Reward == nil || request . Reward . Type == "" {
return cost
}
newCost := * cost // Kopie der ursprünglichen Kosten
switch request . Reward . Type {
case "free_learning" :
// Kostenlose Fertigkeiten: Nur Geld ist 0, EP/LE bleiben
if request . Type == "skill" && request . Action == "learn" {
newCost . Money = 0
}
case "free_spell_learning" :
// Kostenlose Zauber: Nur LE ist 0, EP/Geld bleiben
if request . Type == "spell" && request . Action == "learn" {
newCost . LE = 0
}
case "half_ep_improvement" :
// Halbe EP für Verbesserungen
if request . Action == "improve" {
newCost . Ep = newCost . Ep / 2
}
case "gold_for_ep" :
// Gold statt EP verwenden (10 GS = 1 EP)
if request . Reward . UseGoldForEP && newCost . Ep > 0 {
maxGoldEP := request . Reward . MaxGoldEP
if maxGoldEP == 0 {
// Standard: Maximal die Hälfte der EP durch Gold ersetzen
maxGoldEP = newCost . Ep / 2
}
// Beschränke auf verfügbare EP
if maxGoldEP > newCost . Ep {
maxGoldEP = newCost . Ep
}
// Ersetze EP durch Gold (10 GS pro EP)
newCost . Ep -= maxGoldEP
newCost . Money += maxGoldEP * 10
}
}
return & newCost
}
// Helper structures and functions
type skillInfo struct {
Category string
Difficulty string
}
func getSpellInfo ( spellName string ) skillInfo {
2025-07-27 23:50:19 +02:00
var spell models . Spell
2025-07-24 07:39:43 +02:00
if err := spell . First ( spellName ) ; err != nil {
return skillInfo { Category : "unknown" , Difficulty : "unknown" }
}
return skillInfo { Category : spell . Category , Difficulty : strconv . Itoa ( spell . Stufe ) }
}
2025-07-28 21:35:29 +02:00
func canCharacterAfford ( character * models . Char , cost * models . LearnCost ) bool {
2025-07-24 07:39:43 +02:00
// Check if character has enough EP
2025-07-25 20:43:28 +02:00
if character . Erfahrungsschatz . EP < cost . Ep {
2025-07-24 07:39:43 +02:00
return false
}
// Check if character has enough money
// Assuming money is stored in Bennies (Gold pieces)
totalMoney := character . Bennies . Gg + character . Bennies . Gp + character . Bennies . Sg
return totalMoney >= cost . Money
}
2025-07-28 21:35:29 +02:00
func generateNotes ( character * models . Char , request * SkillCostRequest , cost * models . LearnCost ) string {
2025-07-24 07:39:43 +02:00
var notes [ ] string
if request . Action == "learn" {
notes = append ( notes , "Neue Fertigkeit erlernen" )
} else {
notes = append ( notes , fmt . Sprintf ( "Verbesserung von %d auf %d" , request . CurrentLevel , request . CurrentLevel + 1 ) )
}
// Add character class specific notes
if character . Typ != "" {
notes = append ( notes , fmt . Sprintf ( "Kosten für %s" , character . Typ ) )
}
// Add PP usage notes
if request . UsePP > 0 {
notes = append ( notes , fmt . Sprintf ( "Verwendung von %d Praxispunkten" , request . UsePP ) )
}
// Add affordability note
if ! canCharacterAfford ( character , cost ) {
notes = append ( notes , "Nicht genügend EP oder Gold vorhanden" )
}
return strings . Join ( notes , ". " )
}
// getPPForSkill ermittelt die verfügbaren Praxispunkte für eine spezifische Fertigkeit
2025-07-28 21:35:29 +02:00
func getPPForSkill ( character * models . Char , skillName string ) int {
2025-07-24 07:39:43 +02:00
// Ermittle die tatsächliche Fertigkeit (bei Zaubern die Zaubergruppe)
2025-08-01 07:19:02 +02:00
targetSkillName := getSpellCategoryNewSystem ( skillName )
2025-07-24 07:39:43 +02:00
for _ , fertigkeit := range character . Fertigkeiten {
if fertigkeit . Name == targetSkillName {
return fertigkeit . Pp
}
}
return 0
}
// applyPPReduction reduziert die Kosten entsprechend der verwendeten Praxispunkte
2025-07-27 23:31:04 +02:00
func applyPPReduction ( request * SkillCostRequest , cost * models . LearnCost , availablePP int ) ( int , int , int ) {
2025-07-24 07:39:43 +02:00
if request . UsePP <= 0 {
return cost . Ep , cost . LE , 0
}
// Maximal so viele PP verwenden, wie verfügbar sind
ppToUse := request . UsePP
if ppToUse > availablePP {
ppToUse = availablePP
}
originalEP := cost . Ep
originalLE := cost . LE
var finalEP , finalLE int
var reduction int
if request . Action == "improve" {
// Für Verbesserungen: 1 TE für 1 PP
// Jeder PP ersetzt 1 TE, daher wird die entsprechende EP-Menge reduziert
reduction = ppToUse // PP-Punkte direkt als Reduktion verwenden
finalEP = originalEP - reduction
finalLE = originalLE
if finalEP < 0 {
finalEP = 0
}
} else if request . Action == "learn" && request . Type == "spell" {
// Für Zauber lernen: 1 LE für 1 PP
reduction = ppToUse // PP-Punkte direkt als Reduktion verwenden
finalLE = originalLE - reduction
finalEP = originalEP
if finalLE < 0 {
finalLE = 0
}
} else {
// Für andere Lernfälle: keine PP-Reduktion
finalEP = originalEP
finalLE = originalLE
reduction = 0
}
return finalEP , finalLE , reduction
}