diff options
Diffstat (limited to 'internal/validate/checks.go')
| -rw-r--r-- | internal/validate/checks.go | 64 |
1 files changed, 63 insertions, 1 deletions
diff --git a/internal/validate/checks.go b/internal/validate/checks.go index 1c87c67..6341108 100644 --- a/internal/validate/checks.go +++ b/internal/validate/checks.go @@ -9,6 +9,7 @@ import ( "sort" "strings" + "gopkg.in/yaml.v3" "thehouseoficarus/internal/behavior" "thehouseoficarus/internal/casino" "thehouseoficarus/internal/color" @@ -132,6 +133,24 @@ func validateRooms(s Source) []Issue { id, sp.ID), }) } + // A non-positive quantity is silently skipped by every ground-item + // read path, so the spawn is dead content with no feedback. + if sp.Quantity <= 0 { + issues = append(issues, Issue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Room %d: item spawn %q has quantity %d; it must be positive or the spawn can never appear", + id, sp.ID, sp.Quantity), + }) + } + if sp.RespawnTicks < 0 { + issues = append(issues, Issue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Room %d: item spawn %q has negative respawn_ticks %.1f", + id, sp.ID, sp.RespawnTicks), + }) + } } var collEntries []roomObjEntry @@ -1180,8 +1199,51 @@ func validateCourses(s Source) []Issue { return issues } +// validateFlagTriggerFiles validates every file-backed flag trigger under +// data/triggers. A file that sets neither on_player_flag nor on_global_flag is +// loaded but indexed nowhere and can never fire, so it is an ERROR; the steps +// are checked for dangling references like any other trigger block. +func validateFlagTriggerFiles(s Source) []Issue { + var issues []Issue + roomIndex := s.World.RoomIndex() + itemIDs := s.Items.IDSet() + mobIDs := s.Mobs.AllDefIDs() + dropIDs := dropTableIDSet(s.DataDir) + dir := filepath.Join(s.DataDir, "triggers") + if err := behavior.WalkYAMLDir(dir, func(path, id string, data []byte) error { + var t behavior.Trigger + if err := yaml.Unmarshal(data, &t); err != nil { + // validateKnownFields already reports the decode error. + return nil + } + rel := strings.TrimPrefix(filepath.ToSlash(path), filepath.ToSlash(s.DataDir)+"/") + if t.OnPlayerFlag == "" && t.OnGlobalFlag == "" { + issues = append(issues, Issue{ + Level: "ERROR", + Type: "trigger", + Message: fmt.Sprintf("trigger %s: neither on_player_flag nor on_global_flag is set, so it is never indexed and can never fire", rel), + }) + return nil + } + if t.Condition != nil { + issues = append(issues, validateCondition(rel, t.Condition, roomIndex, itemIDs)...) + } + for si := range t.Steps { + issues = append(issues, validateStep(fmt.Sprintf("%s: step[%d]", rel, si), &t.Steps[si], itemIDs, roomIndex, mobIDs, dropIDs)...) + } + return nil + }); err != nil { + issues = append(issues, Issue{ + Level: "ERROR", + Type: "trigger", + Message: fmt.Sprintf("triggers: could not scan trigger files: %v", err), + }) + } + return issues +} + // validateRoomTriggers validates the on_enter and on_exit trigger blocks on -// every room. Flag-change triggers (data/triggers) are not validated here. +// every room. Flag-change triggers (data/triggers) are validated separately. func validateRoomTriggers(s Source) []Issue { var issues []Issue roomIndex := s.World.RoomIndex() |
