aboutsummaryrefslogtreecommitdiff
path: root/internal/validate/checks.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/validate/checks.go')
-rw-r--r--internal/validate/checks.go64
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()