From fbaa8e2dccbfd857ba16d6537790d285214bdce9 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 19 Dec 2025 17:28:40 +0100 Subject: [PATCH] Show right values for Weapons --- backend/pdfrender/mapper.go | 67 ++++++++++++-- backend/pdfrender/weapon_mapper_test.go | 115 ++++++++++++++++++++++++ 2 files changed, 173 insertions(+), 9 deletions(-) create mode 100644 backend/pdfrender/weapon_mapper_test.go diff --git a/backend/pdfrender/mapper.go b/backend/pdfrender/mapper.go index 45c6675..552a5b1 100644 --- a/backend/pdfrender/mapper.go +++ b/backend/pdfrender/mapper.go @@ -93,11 +93,16 @@ func mapAttributes(char *models.Char) AttributeValues { // mapDerivedValues extracts derived values like LP, AP, etc. func mapDerivedValues(char *models.Char) DerivedValueSet { + // Get attributes for bonus calculations + attrs := mapAttributes(char) + return DerivedValueSet{ - LPMax: char.Lp.Max, - LPAktuell: char.Lp.Value, - APMax: char.Ap.Max, - APAktuell: char.Ap.Value, + LPMax: char.Lp.Max, + LPAktuell: char.Lp.Value, + APMax: char.Ap.Max, + APAktuell: char.Ap.Value, + AngriffBonus: calculateAttributeBonus(attrs.Gs), + SchadenBonus: (attrs.St / 20) + (attrs.Gs / 30) - 3, } } @@ -120,14 +125,41 @@ func mapSkills(char *models.Char) []SkillViewModel { } // mapWeapons converts character weapon skills to WeaponViewModel +// EW = Waffenfertigkeit.Fertigkeitswert + Character.AngriffBonus + Weapon.Anb func mapWeapons(char *models.Char) []WeaponViewModel { weapons := make([]WeaponViewModel, 0, len(char.Waffenfertigkeiten)) - for _, weapon := range char.Waffenfertigkeiten { - weapons = append(weapons, WeaponViewModel{ - Name: weapon.Name, - Value: weapon.Fertigkeitswert, - }) + // Calculate character's attack bonus once + attrs := mapAttributes(char) + angriffsBonus := calculateAttributeBonus(attrs.Gs) + // schadenBonus will be used later for damage calculation + // schadenBonus := (attrs.St / 20) + (attrs.Gs / 30) - 3 + + // Create a map of equipped weapons for quick lookup + equippedWeapons := make(map[string]*models.EqWaffe) + for i := range char.Waffen { + equippedWeapons[char.Waffen[i].Name] = &char.Waffen[i] + } + + for _, weaponSkill := range char.Waffenfertigkeiten { + vm := WeaponViewModel{ + Name: weaponSkill.Name, + Value: weaponSkill.Fertigkeitswert, // Base skill value + } + + // If character has this weapon equipped, add weapon bonuses + if equippedWeapon, exists := equippedWeapons[weaponSkill.Name]; exists { + // EW = skill + character attack bonus + weapon attack bonus + vm.Value += angriffsBonus + equippedWeapon.Anb + + // TODO: Calculate damage including weapon and character bonuses + // TODO: Add range information for ranged weapons + } else { + // No equipped weapon, just use skill + character bonus + vm.Value += angriffsBonus + } + + weapons = append(weapons, vm) } return weapons @@ -214,3 +246,20 @@ func mapEquipment(char *models.Char) []EquipmentViewModel { return equipment } + +// calculateAttributeBonus calculates attribute bonus based on value +// Same logic as in character/derived_values_calculator.go +func calculateAttributeBonus(value int) int { + if value >= 1 && value <= 5 { + return -2 + } else if value >= 6 && value <= 20 { + return -1 + } else if value >= 21 && value <= 80 { + return 0 + } else if value >= 81 && value <= 95 { + return 1 + } else if value >= 96 && value <= 100 { + return 2 + } + return 0 +} diff --git a/backend/pdfrender/weapon_mapper_test.go b/backend/pdfrender/weapon_mapper_test.go new file mode 100644 index 0000000..2ad0b86 --- /dev/null +++ b/backend/pdfrender/weapon_mapper_test.go @@ -0,0 +1,115 @@ +package pdfrender + +import ( + "bamort/models" + "testing" +) + +// TestMapWeapons_WithEWCalculation tests that weapon EW is correctly calculated +// EW = Waffenfertigkeit.Fertigkeitswert + Character.AngriffBonus + Weapon.Anb +func TestMapWeapons_WithEWCalculation(t *testing.T) { + // Arrange - Create a character with weapon skills and equipped weapons + char := &models.Char{ + BamortBase: models.BamortBase{ + ID: 1, + Name: "Test Fighter", + }, + // Weapon skills the character has learned + Waffenfertigkeiten: []models.SkWaffenfertigkeit{ + { + SkFertigkeit: models.SkFertigkeit{ + BamortCharTrait: models.BamortCharTrait{ + BamortBase: models.BamortBase{ + Name: "Langschwert", + }, + }, + Fertigkeitswert: 12, // Base skill value + }, + }, + { + SkFertigkeit: models.SkFertigkeit{ + BamortCharTrait: models.BamortCharTrait{ + BamortBase: models.BamortBase{ + Name: "Bogen", + }, + }, + Fertigkeitswert: 10, + }, + }, + }, + // Actual equipped weapons with bonuses + Waffen: []models.EqWaffe{ + { + BamortCharTrait: models.BamortCharTrait{ + BamortBase: models.BamortBase{ + Name: "Langschwert", + }, + }, + Anb: 2, // Attack bonus of weapon + Schb: 1, // Damage bonus of weapon + }, + { + BamortCharTrait: models.BamortCharTrait{ + BamortBase: models.BamortBase{ + Name: "Bogen", + }, + }, + Anb: 0, + Schb: 0, + }, + }, + // Character attributes that influence combat + Eigenschaften: []models.Eigenschaft{ + {Name: "St", Value: 90}, // Strength influences attack bonus + {Name: "Gw", Value: 80}, // Dexterity influences attack bonus + }, + } + + // Act + vm, err := MapCharacterToViewModel(char) + + // Assert + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + if len(vm.Weapons) != 2 { + t.Fatalf("Expected 2 weapons, got %d", len(vm.Weapons)) + } + + // Test Langschwert + sword := vm.Weapons[0] + if sword.Name != "Langschwert" { + t.Errorf("Expected weapon name 'Langschwert', got '%s'", sword.Name) + } + + // EW should be: skill(12) + char_attack_bonus + weapon_bonus(2) + // Character attack bonus is derived from St/Gw, typically calculated in DerivedValues + // For now, we expect at least: 12 + 2 = 14 (we'll enhance with char bonus later) + if sword.Value < 14 { + t.Errorf("Expected sword EW >= 14 (skill 12 + weapon bonus 2), got %d", sword.Value) + } + + // Test Bogen + bow := vm.Weapons[1] + if bow.Name != "Bogen" { + t.Errorf("Expected weapon name 'Bogen', got '%s'", bow.Name) + } + + if bow.Value < 10 { + t.Errorf("Expected bow EW >= 10 (skill 10 + no weapon bonus), got %d", bow.Value) + } +} + +// TestMapWeapons_WithDamageCalculation tests that weapon damage is correctly calculated +func TestMapWeapons_WithDamageCalculation(t *testing.T) { + // This test will be implemented to verify damage calculation + // For now, we mark it as a placeholder for TDD + t.Skip("TODO: Implement damage calculation test") +} + +// TestMapWeapons_WithRangedWeaponRanges tests that ranged weapons show their ranges +func TestMapWeapons_WithRangedWeaponRanges(t *testing.T) { + // This test will verify that ranged weapons (Bogen, Armbrust) show ranges + t.Skip("TODO: Implement ranged weapon ranges test") +}