042a1d4773
* introduced central package registry by package init function * dynamic registration of routes, model, migrations and initializers. * setting a docker compose project name to prevent shutdown of other containers with the same (composer)name * ai documentation * app template * Create tests for ALL API entpoints in ALL packages Based on current data. Ensure that all API endpoints used in frontend are tested. These tests are crucial for the next refactoring tasks. * adopting agent instructions for a more consistent coding style * added desired module layout and debugging information * Fix All Failing tests All failing tests are fixed now that makes the refactoring more easy since all tests must pass * restored routes for maintenance * added common translations * added new tests for API Endpoint * Merge branch 'separate_business_logic' * added lern and skill improvement cost editing * Set Docker image tag when building to prevent rebuild when nothing has changed * add and remove PP for Weaponskill fixed * add and remove PP for same named skills fixed * add new task
392 lines
12 KiB
Go
392 lines
12 KiB
Go
package character
|
|
|
|
import (
|
|
"bamort/bmrt/models"
|
|
"bamort/database"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// PracticePointResponse repräsentiert die Antwort für Praxispunkte einer Fertigkeit
|
|
type PracticePointResponse struct {
|
|
SkillName string `json:"skill_name"`
|
|
SkillDescription string `json:"skill_description,omitempty"`
|
|
Amount int `json:"amount"`
|
|
}
|
|
|
|
// PracticePointActionResponse repräsentiert die erweiterte Antwort für PP-Aktionen
|
|
type PracticePointActionResponse struct {
|
|
Success bool `json:"success"`
|
|
Message string `json:"message"`
|
|
RequestedSkill string `json:"requested_skill"` // Ursprünglich angefragter Name
|
|
TargetSkill string `json:"target_skill"` // Tatsächlich betroffene Fertigkeit
|
|
IsSpell bool `json:"is_spell"` // Ob es sich um einen Zauber handelt
|
|
PracticePoints []PracticePointResponse `json:"practice_points"` // Aktuelle PP-Liste
|
|
}
|
|
|
|
// GetPracticePoints gibt die verfügbaren Praxispunkte eines Charakters zurück
|
|
func GetPracticePoints(c *gin.Context) {
|
|
// Charakter-ID aus der URL abrufen
|
|
charID := c.Param("id")
|
|
|
|
// Charakter aus der Datenbank laden
|
|
var character models.Char
|
|
if err := character.FirstID(charID); err != nil {
|
|
respondWithError(c, http.StatusNotFound, "Charakter nicht gefunden")
|
|
return
|
|
}
|
|
|
|
// Praxispunkte aus den Fertigkeiten extrahieren
|
|
var practicePoints []PracticePointResponse
|
|
for _, skill := range character.Fertigkeiten {
|
|
if skill.Pp > 0 {
|
|
practicePoints = append(practicePoints, PracticePointResponse{
|
|
SkillName: skill.Name,
|
|
SkillDescription: skill.Beschreibung,
|
|
Amount: skill.Pp,
|
|
})
|
|
}
|
|
}
|
|
for _, skill := range character.Waffenfertigkeiten {
|
|
if skill.Pp > 0 {
|
|
practicePoints = append(practicePoints, PracticePointResponse{
|
|
SkillName: skill.Name,
|
|
SkillDescription: skill.Beschreibung,
|
|
Amount: skill.Pp,
|
|
})
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, practicePoints)
|
|
}
|
|
|
|
// UpdatePracticePoints aktualisiert die Praxispunkte eines Charakters
|
|
func UpdatePracticePoints(c *gin.Context) {
|
|
// Charakter-ID aus der URL abrufen
|
|
charID := c.Param("id")
|
|
|
|
// Charakter aus der Datenbank laden
|
|
var character models.Char
|
|
if err := character.FirstID(charID); err != nil {
|
|
respondWithError(c, http.StatusNotFound, "Charakter nicht gefunden")
|
|
return
|
|
}
|
|
|
|
// Check ownership
|
|
if !checkCharacterOwnership(c, &character) {
|
|
return
|
|
}
|
|
|
|
// Request-Parameter abrufen
|
|
var practicePoints []PracticePointResponse
|
|
if err := c.ShouldBindJSON(&practicePoints); err != nil {
|
|
respondWithError(c, http.StatusBadRequest, "Ungültige Praxispunkt-Daten: "+err.Error())
|
|
return
|
|
}
|
|
|
|
// Alle Fertigkeiten durchgehen und Praxispunkte zurücksetzen
|
|
/*
|
|
for i := range character.Fertigkeiten {
|
|
character.Fertigkeiten[i].Pp = 0
|
|
}
|
|
*/
|
|
|
|
// Neue Praxispunkte setzen
|
|
for _, pp := range practicePoints {
|
|
for i := range character.Fertigkeiten {
|
|
if character.Fertigkeiten[i].Name == pp.SkillName {
|
|
character.Fertigkeiten[i].Pp = pp.Amount
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// Charakter in der Datenbank speichern
|
|
if err := database.DB.Save(&character).Error; err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Fehler beim Speichern der Praxispunkte: "+err.Error())
|
|
return
|
|
}
|
|
|
|
// Aktualisierte Praxispunkte zurückgeben
|
|
var updatedPracticePoints []PracticePointResponse
|
|
for _, skill := range character.Fertigkeiten {
|
|
if skill.Pp > 0 {
|
|
updatedPracticePoints = append(updatedPracticePoints, PracticePointResponse{
|
|
SkillName: skill.Name,
|
|
Amount: skill.Pp,
|
|
})
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, updatedPracticePoints)
|
|
}
|
|
|
|
// AddPracticePoint fügt einen Praxispunkt zu einer Fertigkeit hinzu
|
|
// TODO prüfe speichern der PP für Spells
|
|
func AddPracticePoint(c *gin.Context) {
|
|
// Charakter-ID aus der URL abrufen
|
|
charID := c.Param("id")
|
|
|
|
// Charakter aus der Datenbank laden
|
|
var character models.Char
|
|
if err := character.FirstID(charID); err != nil {
|
|
respondWithError(c, http.StatusNotFound, "Charakter nicht gefunden")
|
|
return
|
|
}
|
|
|
|
// Check ownership
|
|
if !checkCharacterOwnership(c, &character) {
|
|
return
|
|
}
|
|
|
|
// Request-Parameter abrufen
|
|
type AddPPRequest struct {
|
|
SkillName string `json:"skill_name" binding:"required"`
|
|
SkillDescription string `json:"skill_description"`
|
|
Amount int `json:"amount"`
|
|
}
|
|
|
|
var request AddPPRequest
|
|
if err := c.ShouldBindJSON(&request); err != nil {
|
|
respondWithError(c, http.StatusBadRequest, "Ungültige Anfrageparameter: "+err.Error())
|
|
return
|
|
}
|
|
|
|
if request.Amount <= 0 {
|
|
request.Amount = 1
|
|
}
|
|
|
|
// Prüfen, ob es sich um einen Zauber handelt
|
|
var targetSkillName string
|
|
var isSpellFlag bool
|
|
if isSpellNewSystem(request.SkillName) {
|
|
// Bei Zaubern: PP werden der entsprechenden Zaubergruppe zugeordnet
|
|
targetSkillName = getSpellCategoryNewSystem(request.SkillName)
|
|
isSpellFlag = true
|
|
} else {
|
|
// Bei normalen Fertigkeiten: PP werden direkt der Fertigkeit zugeordnet
|
|
targetSkillName = request.SkillName
|
|
isSpellFlag = false
|
|
}
|
|
|
|
// skillMatches prüft ob Name übereinstimmt und (wenn angegeben) auch die Beschreibung.
|
|
skillMatchesAdd := func(name, beschreibung string) bool {
|
|
if name != targetSkillName {
|
|
return false
|
|
}
|
|
if request.SkillDescription != "" && beschreibung != request.SkillDescription {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Praxispunkt zur entsprechenden Fertigkeit hinzufügen und sofort speichern
|
|
foundSkill := false
|
|
for i := range character.Fertigkeiten {
|
|
if skillMatchesAdd(character.Fertigkeiten[i].Name, character.Fertigkeiten[i].Beschreibung) {
|
|
character.Fertigkeiten[i].Pp += request.Amount
|
|
if err := database.DB.Save(&character.Fertigkeiten[i]).Error; err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Fehler beim Speichern der Fertigkeit: "+err.Error())
|
|
return
|
|
}
|
|
foundSkill = true
|
|
break
|
|
}
|
|
}
|
|
foundWeaponSkill := false
|
|
for i := range character.Waffenfertigkeiten {
|
|
if skillMatchesAdd(character.Waffenfertigkeiten[i].Name, character.Waffenfertigkeiten[i].Beschreibung) {
|
|
character.Waffenfertigkeiten[i].Pp += request.Amount
|
|
if err := database.DB.Save(&character.Waffenfertigkeiten[i]).Error; err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Fehler beim Speichern der Waffenfertigkeit: "+err.Error())
|
|
return
|
|
}
|
|
foundWeaponSkill = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !foundSkill && !foundWeaponSkill {
|
|
respondWithError(c, http.StatusBadRequest, "Fertigkeit nicht gefunden: "+targetSkillName)
|
|
return
|
|
}
|
|
|
|
// Aktualisierte Praxispunkte sammeln
|
|
var practicePoints []PracticePointResponse
|
|
for _, skill := range character.Fertigkeiten {
|
|
if skill.Pp > 0 {
|
|
practicePoints = append(practicePoints, PracticePointResponse{
|
|
SkillName: skill.Name,
|
|
SkillDescription: skill.Beschreibung,
|
|
Amount: skill.Pp,
|
|
})
|
|
}
|
|
}
|
|
|
|
for _, skill := range character.Waffenfertigkeiten {
|
|
if skill.Pp > 0 {
|
|
practicePoints = append(practicePoints, PracticePointResponse{
|
|
SkillName: skill.Name,
|
|
SkillDescription: skill.Beschreibung,
|
|
Amount: skill.Pp,
|
|
})
|
|
}
|
|
}
|
|
|
|
// Erfolgreiche Response mit Details zurückgeben
|
|
var message string
|
|
if isSpellFlag {
|
|
message = "Praxispunkt für Zauber '" + request.SkillName + "' wurde der Zaubergruppe '" + targetSkillName + "' hinzugefügt"
|
|
} else if foundSkill {
|
|
message = "Praxispunkt für Fertigkeit '" + targetSkillName + "' hinzugefügt"
|
|
} else if foundWeaponSkill {
|
|
message = "Praxispunkt für Waffenfertigkeit '" + targetSkillName + "' hinzugefügt"
|
|
}
|
|
|
|
response := PracticePointActionResponse{
|
|
Success: true,
|
|
Message: message,
|
|
RequestedSkill: request.SkillName,
|
|
TargetSkill: targetSkillName,
|
|
IsSpell: isSpellFlag,
|
|
PracticePoints: practicePoints,
|
|
}
|
|
|
|
c.JSON(http.StatusOK, response)
|
|
}
|
|
|
|
// UsePracticePoint verbraucht Praxispunkte für eine spezifische Fertigkeit
|
|
func UsePracticePoint(c *gin.Context) {
|
|
// Charakter-ID aus der URL abrufen
|
|
charID := c.Param("id")
|
|
|
|
// Charakter aus der Datenbank laden
|
|
var character models.Char
|
|
if err := character.FirstID(charID); err != nil {
|
|
respondWithError(c, http.StatusNotFound, "Charakter nicht gefunden")
|
|
return
|
|
}
|
|
|
|
// Check ownership
|
|
if !checkCharacterOwnership(c, &character) {
|
|
return
|
|
}
|
|
|
|
// Request-Parameter abrufen
|
|
type UsePPRequest struct {
|
|
SkillName string `json:"skill_name" binding:"required"`
|
|
SkillDescription string `json:"skill_description"`
|
|
Amount int `json:"amount"`
|
|
}
|
|
|
|
var request UsePPRequest
|
|
if err := c.ShouldBindJSON(&request); err != nil {
|
|
respondWithError(c, http.StatusBadRequest, "Ungültige Anfrageparameter: "+err.Error())
|
|
return
|
|
}
|
|
|
|
if request.Amount <= 0 {
|
|
request.Amount = 1
|
|
}
|
|
|
|
// Prüfen, ob es sich um einen Zauber handelt
|
|
var targetSkillName string
|
|
var isSpellFlag bool
|
|
if isSpellNewSystem(request.SkillName) {
|
|
// Bei Zaubern: PP werden von der entsprechenden Zaubergruppe abgezogen
|
|
targetSkillName = getSpellCategoryNewSystem(request.SkillName)
|
|
isSpellFlag = true
|
|
} else {
|
|
// Bei normalen Fertigkeiten: PP werden direkt von der Fertigkeit abgezogen
|
|
targetSkillName = request.SkillName
|
|
isSpellFlag = false
|
|
}
|
|
|
|
// skillMatchesUse prüft ob Name übereinstimmt und (wenn angegeben) auch die Beschreibung.
|
|
skillMatchesUse := func(name, beschreibung string) bool {
|
|
if name != targetSkillName {
|
|
return false
|
|
}
|
|
if request.SkillDescription != "" && beschreibung != request.SkillDescription {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Praxispunkt von der entsprechenden Fertigkeit abziehen und sofort speichern
|
|
foundSkill := false
|
|
for i := range character.Fertigkeiten {
|
|
if skillMatchesUse(character.Fertigkeiten[i].Name, character.Fertigkeiten[i].Beschreibung) {
|
|
if character.Fertigkeiten[i].Pp >= request.Amount {
|
|
character.Fertigkeiten[i].Pp -= request.Amount
|
|
if err := database.DB.Save(&character.Fertigkeiten[i]).Error; err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Fehler beim Speichern der Fertigkeit: "+err.Error())
|
|
return
|
|
}
|
|
foundSkill = true
|
|
} else {
|
|
respondWithError(c, http.StatusBadRequest, "Nicht genügend Praxispunkte verfügbar")
|
|
return
|
|
}
|
|
break
|
|
}
|
|
}
|
|
foundWeaponSkill := false
|
|
for i := range character.Waffenfertigkeiten {
|
|
if skillMatchesUse(character.Waffenfertigkeiten[i].Name, character.Waffenfertigkeiten[i].Beschreibung) {
|
|
if character.Waffenfertigkeiten[i].Pp >= request.Amount {
|
|
character.Waffenfertigkeiten[i].Pp -= request.Amount
|
|
if err := database.DB.Save(&character.Waffenfertigkeiten[i]).Error; err != nil {
|
|
respondWithError(c, http.StatusInternalServerError, "Fehler beim Speichern der Waffenfertigkeit: "+err.Error())
|
|
return
|
|
}
|
|
foundWeaponSkill = true
|
|
} else {
|
|
respondWithError(c, http.StatusBadRequest, "Nicht genügend Praxispunkte verfügbar")
|
|
return
|
|
}
|
|
break
|
|
}
|
|
}
|
|
|
|
if !foundSkill && !foundWeaponSkill {
|
|
respondWithError(c, http.StatusBadRequest, "Fertigkeit nicht gefunden: "+targetSkillName)
|
|
return
|
|
}
|
|
|
|
// Erfolgreiche Antwort mit detaillierten Informationen und aktueller PP-Liste
|
|
var practicePoints []PracticePointResponse
|
|
for _, skill := range character.Fertigkeiten {
|
|
if skill.Pp > 0 {
|
|
practicePoints = append(practicePoints, PracticePointResponse{
|
|
SkillName: skill.Name,
|
|
SkillDescription: skill.Beschreibung,
|
|
Amount: skill.Pp,
|
|
})
|
|
}
|
|
}
|
|
|
|
for _, skill := range character.Waffenfertigkeiten {
|
|
if skill.Pp > 0 {
|
|
practicePoints = append(practicePoints, PracticePointResponse{
|
|
SkillName: skill.Name,
|
|
SkillDescription: skill.Beschreibung,
|
|
Amount: skill.Pp,
|
|
})
|
|
}
|
|
}
|
|
|
|
response := PracticePointActionResponse{
|
|
Success: true,
|
|
Message: fmt.Sprintf("%d Praxispunkte erfolgreich von %s verwendet/reduziert", request.Amount, targetSkillName),
|
|
RequestedSkill: request.SkillName,
|
|
TargetSkill: targetSkillName,
|
|
IsSpell: isSpellFlag,
|
|
PracticePoints: practicePoints,
|
|
}
|
|
|
|
c.JSON(http.StatusOK, response)
|
|
}
|