diff options
Diffstat (limited to 'internal/validate/checks.go')
| -rw-r--r-- | internal/validate/checks.go | 59 |
1 files changed, 57 insertions, 2 deletions
diff --git a/internal/validate/checks.go b/internal/validate/checks.go index a8f973f..ccf996c 100644 --- a/internal/validate/checks.go +++ b/internal/validate/checks.go @@ -7,6 +7,7 @@ import ( "thehouseoficarus/internal/behavior" "thehouseoficarus/internal/color" + "thehouseoficarus/internal/combat" "thehouseoficarus/internal/world" ) @@ -292,6 +293,57 @@ func validateRoomObjectCollisions(roomID int, entries []roomObjEntry) []Issue { return issues } +// validateMobAttackTypes enforces the mob attack_types spec: a non-empty list +// containing exactly one melee type (stab/slash/crush) plus at most one each of +// the optional ranged/science types, with no invalid or duplicate entries. +func validateMobAttackTypes(id string, types []string) []Issue { + var issues []Issue + + if len(types) == 0 { + issues = append(issues, Issue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Mob %q: missing attack_types (must be a list with exactly one of stab/slash/crush, optionally plus ranged/science)", id), + }) + return issues + } + + meleeCount := 0 + seen := map[string]bool{} + for _, t := range types { + if !combat.IsValidAttackType(t) { + issues = append(issues, Issue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Mob %q: invalid attack_types entry %q (must be stab/slash/crush/ranged/science)", id, t), + }) + continue + } + if seen[t] { + issues = append(issues, Issue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Mob %q: duplicate attack_types entry %q", id, t), + }) + continue + } + seen[t] = true + if combat.IsMeleeType(t) { + meleeCount++ + } + } + + if meleeCount != 1 { + issues = append(issues, Issue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Mob %q: attack_types must contain exactly one melee type (stab/slash/crush), found %d", id, meleeCount), + }) + } + + return issues +} + func validateMobs(s Source) []Issue { var issues []Issue itemIDs := s.Items.IDSet() @@ -336,6 +388,10 @@ func validateMobs(s Source) []Issue { }) } + if def.Combat != nil && def.Combat.Kind != "task" { + issues = append(issues, validateMobAttackTypes(id, def.Combat.AttackTypes)...) + } + if def.Drops.Remains != "" && !itemIDs[def.Drops.Remains] { issues = append(issues, Issue{ Level: "ERROR", @@ -427,7 +483,6 @@ func validateMobs(s Source) []Issue { func validateHazards(s Source) []Issue { var issues []Issue itemIDs := s.Items.IDSet() - validTypes := map[string]bool{"stab": true, "slash": true, "crush": true, "ranged": true, "science": true} for id := range s.World.HazardIndex() { def, err := s.World.LoadHazard(id) @@ -439,7 +494,7 @@ func validateHazards(s Source) []Issue { }) continue } - if def.AttackType != "" && !validTypes[def.AttackType] { + if def.AttackType != "" && !combat.IsValidAttackType(def.AttackType) { issues = append(issues, Issue{ Level: "ERROR", Type: "reference", |
