2025-12-19 17:28:40 +01:00
|
|
|
package pdfrender
|
|
|
|
|
|
|
|
|
|
import (
|
2025-12-20 00:19:20 +01:00
|
|
|
"bamort/database"
|
2025-12-19 17:28:40 +01:00
|
|
|
"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) {
|
2025-12-20 00:19:20 +01:00
|
|
|
// Setup test database
|
|
|
|
|
database.SetupTestDB()
|
|
|
|
|
|
|
|
|
|
// Create weapons in gsmaster with skill requirements
|
|
|
|
|
testSword := &models.Weapon{
|
|
|
|
|
Equipment: models.Equipment{
|
|
|
|
|
GameSystem: "midgard",
|
|
|
|
|
Name: "Langschwert",
|
|
|
|
|
},
|
|
|
|
|
SkillRequired: "Schwerter",
|
|
|
|
|
Damage: "1W6",
|
|
|
|
|
}
|
|
|
|
|
_ = testSword.Create()
|
|
|
|
|
|
|
|
|
|
testBow := &models.Weapon{
|
|
|
|
|
Equipment: models.Equipment{
|
|
|
|
|
GameSystem: "midgard",
|
|
|
|
|
Name: "Langbogen",
|
|
|
|
|
},
|
|
|
|
|
SkillRequired: "Bogen",
|
|
|
|
|
Damage: "1W6",
|
|
|
|
|
}
|
|
|
|
|
_ = testBow.Create()
|
|
|
|
|
|
2025-12-19 17:28:40 +01:00
|
|
|
// 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{
|
2025-12-20 00:19:20 +01:00
|
|
|
Name: "Schwerter",
|
2025-12-19 17:28:40 +01:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
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",
|
|
|
|
|
},
|
|
|
|
|
},
|
2025-12-19 17:29:12 +01:00
|
|
|
Anb: 2, // Attack bonus of weapon
|
|
|
|
|
Schb: 1, // Damage bonus of weapon
|
2025-12-19 17:28:40 +01:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
BamortCharTrait: models.BamortCharTrait{
|
|
|
|
|
BamortBase: models.BamortBase{
|
2025-12-20 00:19:20 +01:00
|
|
|
Name: "Langbogen",
|
2025-12-19 17:28:40 +01:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
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)
|
|
|
|
|
}
|
2025-12-19 17:29:12 +01:00
|
|
|
|
2025-12-19 17:28:40 +01:00
|
|
|
// 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)
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-20 00:19:20 +01:00
|
|
|
// Test Langbogen
|
2025-12-19 17:28:40 +01:00
|
|
|
bow := vm.Weapons[1]
|
2025-12-20 00:19:20 +01:00
|
|
|
if bow.Name != "Langbogen" {
|
|
|
|
|
t.Errorf("Expected weapon name 'Langbogen', got '%s'", bow.Name)
|
2025-12-19 17:28:40 +01:00
|
|
|
}
|
2025-12-19 17:29:12 +01:00
|
|
|
|
2025-12-19 17:28:40 +01:00
|
|
|
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
|
2025-12-20 00:19:20 +01:00
|
|
|
// Damage = Base Weapon Damage + Character SchadenBonus + Weapon Schb
|
2025-12-19 17:28:40 +01:00
|
|
|
func TestMapWeapons_WithDamageCalculation(t *testing.T) {
|
2025-12-20 00:19:20 +01:00
|
|
|
// Setup test database to load weapon data
|
|
|
|
|
database.SetupTestDB()
|
|
|
|
|
|
|
|
|
|
// Create test weapon in gsmaster if it doesn't exist
|
|
|
|
|
testWeapon := &models.Weapon{
|
|
|
|
|
Equipment: models.Equipment{
|
|
|
|
|
GameSystem: "midgard",
|
|
|
|
|
Name: "Langschwert",
|
|
|
|
|
},
|
|
|
|
|
SkillRequired: "Schwerter",
|
|
|
|
|
Damage: "1W6",
|
|
|
|
|
}
|
|
|
|
|
_ = testWeapon.Create() // Ignore error if already exists
|
|
|
|
|
|
|
|
|
|
// Arrange - Create a character with weapons that have damage values
|
|
|
|
|
char := &models.Char{
|
|
|
|
|
BamortBase: models.BamortBase{
|
|
|
|
|
ID: 1,
|
|
|
|
|
Name: "Test Fighter",
|
|
|
|
|
},
|
|
|
|
|
// Weapon skills
|
|
|
|
|
Waffenfertigkeiten: []models.SkWaffenfertigkeit{
|
|
|
|
|
{
|
|
|
|
|
SkFertigkeit: models.SkFertigkeit{
|
|
|
|
|
BamortCharTrait: models.BamortCharTrait{
|
|
|
|
|
BamortBase: models.BamortBase{
|
|
|
|
|
Name: "Schwerter",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Fertigkeitswert: 12,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
// Equipped weapons with damage bonuses
|
|
|
|
|
Waffen: []models.EqWaffe{
|
|
|
|
|
{
|
|
|
|
|
BamortCharTrait: models.BamortCharTrait{
|
|
|
|
|
BamortBase: models.BamortBase{
|
|
|
|
|
Name: "Langschwert",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Schb: 2, // Weapon's damage bonus
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
// Character attributes that influence damage bonus
|
|
|
|
|
Eigenschaften: []models.Eigenschaft{
|
|
|
|
|
{Name: "St", Value: 95}, // High strength gives SchadenBonus = +1
|
|
|
|
|
{Name: "Gw", Value: 80},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Act
|
|
|
|
|
vm, err := MapCharacterToViewModel(char)
|
|
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Expected no error, got %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(vm.Weapons) != 1 {
|
|
|
|
|
t.Fatalf("Expected 1 weapon, got %d", len(vm.Weapons))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sword := vm.Weapons[0]
|
|
|
|
|
|
|
|
|
|
// Damage should be in format like "1W6+3" where the bonus combines
|
|
|
|
|
// Character's SchadenBonus (from St=95 -> +1) + Weapon's Schb (2) = +3
|
|
|
|
|
if sword.Damage == "" {
|
|
|
|
|
t.Error("Expected weapon to have damage value, got empty string")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The damage string should be "1W6+3"
|
|
|
|
|
// Base damage "1W6" + total bonus (+3)
|
|
|
|
|
expectedDamage := "1W6+3"
|
|
|
|
|
if sword.Damage != expectedDamage {
|
|
|
|
|
t.Errorf("Expected damage '%s', got '%s'", expectedDamage, sword.Damage)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t.Logf("✓ Weapon damage correctly calculated: %s (SchadenBonus %d + Weapon Schb 2 = +3)",
|
|
|
|
|
sword.Damage, vm.DerivedValues.SchadenBonus)
|
2025-12-19 17:28:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TestMapWeapons_WithRangedWeaponRanges tests that ranged weapons show their ranges
|
|
|
|
|
func TestMapWeapons_WithRangedWeaponRanges(t *testing.T) {
|
2025-12-20 00:19:20 +01:00
|
|
|
// Setup test database
|
|
|
|
|
database.SetupTestDB()
|
|
|
|
|
|
|
|
|
|
// Delete existing test weapons to ensure clean state
|
|
|
|
|
database.DB.Where("name IN (?, ?)", "Langbogen", "Kurzschwert").Delete(&models.Weapon{})
|
|
|
|
|
|
|
|
|
|
// Create a ranged weapon in gsmaster with range values
|
|
|
|
|
testBow := &models.Weapon{
|
|
|
|
|
Equipment: models.Equipment{
|
|
|
|
|
GameSystem: "midgard",
|
|
|
|
|
Name: "Langbogen",
|
|
|
|
|
},
|
|
|
|
|
SkillRequired: "Bogen",
|
|
|
|
|
Damage: "1W6",
|
|
|
|
|
RangeNear: 10,
|
|
|
|
|
RangeMiddle: 30,
|
|
|
|
|
RangeFar: 100,
|
|
|
|
|
}
|
|
|
|
|
err := testBow.Create()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Failed to create Langbogen: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify the weapon was created
|
|
|
|
|
verifyWeapon := &models.Weapon{}
|
|
|
|
|
verifyErr := verifyWeapon.First("Langbogen")
|
|
|
|
|
if verifyErr != nil || verifyWeapon.ID == 0 {
|
|
|
|
|
t.Fatalf("Failed to create/find Langbogen in database: %v", verifyErr)
|
|
|
|
|
}
|
|
|
|
|
if verifyWeapon.RangeNear != 10 || verifyWeapon.RangeMiddle != 30 || verifyWeapon.RangeFar != 100 {
|
|
|
|
|
t.Fatalf("Langbogen ranges not set correctly: got %d/%d/%d, expected 10/30/100",
|
|
|
|
|
verifyWeapon.RangeNear, verifyWeapon.RangeMiddle, verifyWeapon.RangeFar)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create a melee weapon without ranges
|
|
|
|
|
testSword := &models.Weapon{
|
|
|
|
|
Equipment: models.Equipment{
|
|
|
|
|
GameSystem: "midgard",
|
|
|
|
|
Name: "Kurzschwert",
|
|
|
|
|
},
|
|
|
|
|
SkillRequired: "Schwerter",
|
|
|
|
|
Damage: "1W6+1",
|
|
|
|
|
RangeNear: 0,
|
|
|
|
|
RangeMiddle: 0,
|
|
|
|
|
RangeFar: 0,
|
|
|
|
|
}
|
|
|
|
|
_ = testSword.Create()
|
|
|
|
|
|
|
|
|
|
// Arrange - Character with both ranged and melee weapons
|
|
|
|
|
char := &models.Char{
|
|
|
|
|
BamortBase: models.BamortBase{
|
|
|
|
|
ID: 1,
|
|
|
|
|
Name: "Test Archer",
|
|
|
|
|
},
|
|
|
|
|
Waffenfertigkeiten: []models.SkWaffenfertigkeit{
|
|
|
|
|
{
|
|
|
|
|
SkFertigkeit: models.SkFertigkeit{
|
|
|
|
|
BamortCharTrait: models.BamortCharTrait{
|
|
|
|
|
BamortBase: models.BamortBase{
|
|
|
|
|
Name: "Bogen",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Fertigkeitswert: 14,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
SkFertigkeit: models.SkFertigkeit{
|
|
|
|
|
BamortCharTrait: models.BamortCharTrait{
|
|
|
|
|
BamortBase: models.BamortBase{
|
|
|
|
|
Name: "Schwerter",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Fertigkeitswert: 10,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Waffen: []models.EqWaffe{
|
|
|
|
|
{
|
|
|
|
|
BamortCharTrait: models.BamortCharTrait{
|
|
|
|
|
BamortBase: models.BamortBase{
|
|
|
|
|
Name: "Langbogen",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
BamortCharTrait: models.BamortCharTrait{
|
|
|
|
|
BamortBase: models.BamortBase{
|
|
|
|
|
Name: "Kurzschwert",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Eigenschaften: []models.Eigenschaft{
|
|
|
|
|
{Name: "St", Value: 75},
|
|
|
|
|
{Name: "Gs", Value: 85},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find the bow
|
|
|
|
|
var bow *WeaponViewModel
|
|
|
|
|
var sword *WeaponViewModel
|
|
|
|
|
for i := range vm.Weapons {
|
|
|
|
|
if vm.Weapons[i].Name == "Langbogen" {
|
|
|
|
|
bow = &vm.Weapons[i]
|
|
|
|
|
} else if vm.Weapons[i].Name == "Kurzschwert" {
|
|
|
|
|
sword = &vm.Weapons[i]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test ranged weapon
|
|
|
|
|
if bow == nil {
|
|
|
|
|
t.Fatal("Langbogen not found in weapons")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !bow.IsRanged {
|
|
|
|
|
t.Error("Expected Langbogen to be marked as ranged weapon")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Range should be formatted as "10/30/100" (Nah/Mittel/Fern)
|
|
|
|
|
expectedRange := "10/30/100"
|
|
|
|
|
if bow.Range != expectedRange {
|
|
|
|
|
t.Errorf("Expected bow range '%s', got '%s'", expectedRange, bow.Range)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t.Logf("✓ Ranged weapon ranges: %s", bow.Range)
|
|
|
|
|
|
|
|
|
|
// Test melee weapon
|
|
|
|
|
if sword == nil {
|
|
|
|
|
t.Fatal("Kurzschwert not found in weapons")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if sword.IsRanged {
|
|
|
|
|
t.Error("Expected Kurzschwert not to be marked as ranged weapon")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if sword.Range != "" {
|
|
|
|
|
t.Errorf("Expected melee weapon to have empty range, got '%s'", sword.Range)
|
|
|
|
|
}
|
2025-12-19 17:28:40 +01:00
|
|
|
}
|