aboutsummaryrefslogtreecommitdiff
path: root/internal/validate/checks.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-09-16 17:05:17 -0400
committerhistoria <[not public]>2026-09-16 17:05:17 -0400
commit1dad15698845d370e998f7cc5feb8aece3fab58f (patch)
tree8d58058782de9f422573e1f8efd5d130ce7d1ce9 /internal/validate/checks.go
parenta6cf03a6ae98e4fb675da25046d148e92bcf7206 (diff)
downloadthehouseoficarus-1dad15698845d370e998f7cc5feb8aece3fab58f.tar.gz
refactor: remove dead code, consolidate save/error handling, add lint gate
Diffstat (limited to 'internal/validate/checks.go')
-rw-r--r--internal/validate/checks.go128
1 files changed, 34 insertions, 94 deletions
diff --git a/internal/validate/checks.go b/internal/validate/checks.go
index 6994654..9d09eef 100644
--- a/internal/validate/checks.go
+++ b/internal/validate/checks.go
@@ -1,3 +1,5 @@
+// Package validate runs semantic/reference checks over the game data
+// directory (dangling ids, bad triggers, unreachable wiring) and reports issues.
package validate
import (
@@ -78,7 +80,7 @@ func validateRooms(s Source) []Issue {
}
issues = append(issues, validateTriggerBlock(
fmt.Sprintf("Room %d: exit %q on_traverse", id, dir),
- exit.OnTraverse, false, itemIDs, roomIndex, mobIDs, nil)...)
+ exit.OnTraverse, itemIDs, roomIndex, mobIDs, nil)...)
}
for _, rm := range room.Mobs {
@@ -230,7 +232,7 @@ func validateLocalObject(roomID int, robj world.RoomObject, itemIDs map[string]b
}
if len(def.OnLook) > 0 {
- issues = append(issues, validateTriggerBlock(prefix+": on_look", def.OnLook, false, itemIDs, roomIndex, mobIDs, nil)...)
+ issues = append(issues, validateTriggerBlock(prefix+": on_look", def.OnLook, itemIDs, roomIndex, mobIDs, nil)...)
}
return issues
@@ -495,7 +497,7 @@ func validateMobs(s Source) []Issue {
}
issues = append(issues, validateTriggerBlock(
- fmt.Sprintf("Mob %q: on_kill", id), def.OnKill, false, itemIDs, roomIndex, mobIDs, dropIDs)...)
+ fmt.Sprintf("Mob %q: on_kill", id), def.OnKill, itemIDs, roomIndex, mobIDs, dropIDs)...)
}
return issues
@@ -604,7 +606,7 @@ func validateObjects(s Source) []Issue {
}
issues = append(issues, validateTriggerBlock(
- fmt.Sprintf("Object %q: on_use", id), obj.OnUse, false, itemIDs, roomIndex, mobIDs, dropIDs)...)
+ fmt.Sprintf("Object %q: on_use", id), obj.OnUse, itemIDs, roomIndex, mobIDs, dropIDs)...)
if obj.Gather != nil {
issues = append(issues, validateGather(fmt.Sprintf("Object %q: gather", id), obj.Gather, itemIDs, dropIDs)...)
@@ -615,7 +617,7 @@ func validateObjects(s Source) []Issue {
}
if len(obj.OnLook) > 0 {
- issues = append(issues, validateTriggerBlock(fmt.Sprintf("Object %q: on_look", id), obj.OnLook, false, itemIDs, roomIndex, mobIDs, dropIDs)...)
+ issues = append(issues, validateTriggerBlock(fmt.Sprintf("Object %q: on_look", id), obj.OnLook, itemIDs, roomIndex, mobIDs, dropIDs)...)
}
}
@@ -649,7 +651,7 @@ func validateItems(s Source) []Issue {
if len(def.Search) > 0 {
issues = append(issues, validateTriggerBlock(
- fmt.Sprintf("Item %q: search", id), def.Search, false, itemIDs, roomIndex, mobIDs, dropIDs)...)
+ fmt.Sprintf("Item %q: search", id), def.Search, itemIDs, roomIndex, mobIDs, dropIDs)...)
}
if def.FarmProduct != "" && !itemIDs[def.FarmProduct] {
@@ -866,9 +868,8 @@ func validateCourses(s Source) []Issue {
return issues
}
-// validateRoomTriggers validates every trigger-shaped block on every room:
-// on_enter, on_exit (verb blocks), and on_flag_change / on_global_flag_change
-// (flag blocks, which require on_player_flag/on_global_flag).
+// validateRoomTriggers validates the on_enter and on_exit trigger blocks on
+// every room. Flag-change triggers (data/triggers) are not validated here.
func validateRoomTriggers(s Source) []Issue {
var issues []Issue
roomIndex := s.World.RoomIndex()
@@ -882,11 +883,11 @@ func validateRoomTriggers(s Source) []Issue {
}
if len(room.OnEnter) > 0 {
issues = append(issues, validateTriggerBlock(
- fmt.Sprintf("Room %d: on_enter", id), room.OnEnter, false, itemIDs, roomIndex, mobIDs, nil)...)
+ fmt.Sprintf("Room %d: on_enter", id), room.OnEnter, itemIDs, roomIndex, mobIDs, nil)...)
}
if len(room.OnExit) > 0 {
issues = append(issues, validateTriggerBlock(
- fmt.Sprintf("Room %d: on_exit", id), room.OnExit, false, itemIDs, roomIndex, mobIDs, nil)...)
+ fmt.Sprintf("Room %d: on_exit", id), room.OnExit, itemIDs, roomIndex, mobIDs, nil)...)
}
}
@@ -1379,87 +1380,30 @@ func validateCondition(prefix string, c *behavior.Condition, roomIndex map[int]b
return issues
}
-// checkPlayerOnlyInCondition warns when a global-scope condition uses
-// player-dependent predicates that cannot be evaluated without a player.
-func checkPlayerOnlyInCondition(prefix string, c *behavior.Condition) []Issue {
- if c == nil {
- return nil
- }
- var issues []Issue
- if c.PlayerFlag != "" {
- issues = append(issues, Issue{
- Level: "WARN",
- Type: "semantic",
- Message: fmt.Sprintf("%s: player_flag %q has no effect on global-flag triggers (no player)", prefix, c.PlayerFlag),
- })
- }
- if c.HasItem != "" {
- issues = append(issues, Issue{
- Level: "WARN",
- Type: "semantic",
- Message: fmt.Sprintf("%s: has_item %q has no effect on global-flag triggers (no player)", prefix, c.HasItem),
- })
- }
- if c.MinCredits > 0 {
- issues = append(issues, Issue{
- Level: "WARN",
- Type: "semantic",
- Message: fmt.Sprintf("%s: min_credits has no effect on global-flag triggers (no player)", prefix),
- })
- }
- for i := range c.AllOf {
- issues = append(issues, checkPlayerOnlyInCondition(prefix, &c.AllOf[i])...)
- }
- for i := range c.AnyOf {
- issues = append(issues, checkPlayerOnlyInCondition(prefix, &c.AnyOf[i])...)
- }
- return issues
-}
-
-// validateTriggerBlock validates a list of Trigger entries for one event block.
-// isFlag is true for on_flag_change / on_global_flag_change blocks (which
-// require on_player_flag/on_global_flag and forbid item_id) and false for verb
-// blocks (on_use/on_look/on_kill/on_enter/on_exit/on_traverse), where item_id
-// is checked against itemIDs.
-func validateTriggerBlock(prefix string, block []behavior.Trigger, isFlag bool, itemIDs map[string]bool, roomIndex map[int]bool, mobIDs map[string]bool, dropIDs map[string]bool) []Issue {
+// validateTriggerBlock validates a list of Trigger entries for one verb event
+// block (on_use/on_look/on_kill/on_enter/on_exit/on_traverse), where item_id
+// is checked against itemIDs. Flag-change blocks (data/triggers) are not
+// validated here.
+func validateTriggerBlock(prefix string, block []behavior.Trigger, itemIDs map[string]bool, roomIndex map[int]bool, mobIDs map[string]bool, dropIDs map[string]bool) []Issue {
var issues []Issue
for i := range block {
t := &block[i]
entryPrefix := fmt.Sprintf("%s[%d]", prefix, i)
- if isFlag {
- if t.OnPlayerFlag == "" && t.OnGlobalFlag == "" {
- issues = append(issues, Issue{
- Level: "WARN",
- Type: "semantic",
- Message: fmt.Sprintf("%s: flag-change trigger has no on_player_flag/on_global_flag — it can never fire",
- entryPrefix),
- })
- }
- if t.ItemID != "" {
- issues = append(issues, Issue{
- Level: "WARN",
- Type: "semantic",
- Message: fmt.Sprintf("%s: item_id is ignored on flag-change triggers",
- entryPrefix),
- })
- }
- } else {
- if t.OnPlayerFlag != "" || t.OnGlobalFlag != "" {
- issues = append(issues, Issue{
- Level: "WARN",
- Type: "semantic",
- Message: fmt.Sprintf("%s: on_player_flag/on_global_flag are ignored on verb triggers",
- entryPrefix),
- })
- }
- if t.ItemID != "" && !itemIDs[t.ItemID] {
- issues = append(issues, Issue{
- Level: "ERROR",
- Type: "reference",
- Message: fmt.Sprintf("%s: item_id %q does not exist",
- entryPrefix, t.ItemID),
- })
- }
+ if t.OnPlayerFlag != "" || t.OnGlobalFlag != "" {
+ issues = append(issues, Issue{
+ Level: "WARN",
+ Type: "semantic",
+ Message: fmt.Sprintf("%s: on_player_flag/on_global_flag are ignored on verb triggers",
+ entryPrefix),
+ })
+ }
+ if t.ItemID != "" && !itemIDs[t.ItemID] {
+ issues = append(issues, Issue{
+ Level: "ERROR",
+ Type: "reference",
+ Message: fmt.Sprintf("%s: item_id %q does not exist",
+ entryPrefix, t.ItemID),
+ })
}
if t.Lock && len(t.Steps) == 0 {
issues = append(issues, Issue{
@@ -1471,14 +1415,10 @@ func validateTriggerBlock(prefix string, block []behavior.Trigger, isFlag bool,
if t.Condition != nil {
issues = append(issues, validateCondition(entryPrefix, t.Condition, roomIndex)...)
}
- if isFlag && t.OnGlobalFlag != "" && t.Condition != nil {
- issues = append(issues, checkPlayerOnlyInCondition(entryPrefix, t.Condition)...)
- }
+
for si := range t.Steps {
issues = append(issues, validateStep(fmt.Sprintf("%s: step[%d]", entryPrefix, si), &t.Steps[si], itemIDs, roomIndex, mobIDs, dropIDs)...)
- if isFlag && t.OnGlobalFlag != "" && t.Steps[si].Condition != nil {
- issues = append(issues, checkPlayerOnlyInCondition(fmt.Sprintf("%s: step[%d]", entryPrefix, si), t.Steps[si].Condition)...)
- }
+
}
}
return issues