diff options
Diffstat (limited to 'internal/validate/checks.go')
| -rw-r--r-- | internal/validate/checks.go | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/internal/validate/checks.go b/internal/validate/checks.go index c636b4f..a152956 100644 --- a/internal/validate/checks.go +++ b/internal/validate/checks.go @@ -816,6 +816,17 @@ func validateObjects(s Source) []Issue { return issues } +var validEquipSlots = map[item.EquipSlot]bool{ + item.SlotHead: true, item.SlotNeck: true, item.SlotTorso: true, item.SlotLegs: true, + item.SlotHands: true, item.SlotFeet: true, item.SlotBack: true, item.SlotAmmo: true, + item.SlotMainHand: true, item.SlotOffHand: true, item.SlotRing: true, +} + +var validEquipTypes = map[item.EquipmentType]bool{ + item.EquipMeleeWeapon: true, item.EquipRangedWeapon: true, item.EquipScienceWeapon: true, + item.EquipArmor: true, item.EquipTool: true, item.EquipAmmo: true, +} + func validateItems(s Source) []Issue { var issues []Issue itemIDs := s.Items.IDSet() @@ -842,6 +853,27 @@ func validateItems(s Source) []Issue { }) } + // Equipment fields are free-form YAML; a typo'd slot/type/attack_type + // equips into an invisible slot or grants bonuses from nowhere. + if def.Equipment != nil { + if def.Equipment.Type != "" && !validEquipTypes[def.Equipment.Type] { + issues = append(issues, Issue{Level: "ERROR", Type: "config", + Message: fmt.Sprintf("Item %q: unknown equipment.type %q", id, def.Equipment.Type)}) + } + if def.Equipment.Slot != "" && !validEquipSlots[def.Equipment.Slot] { + issues = append(issues, Issue{Level: "ERROR", Type: "config", + Message: fmt.Sprintf("Item %q: unknown equipment.slot %q", id, def.Equipment.Slot)}) + } + if def.Equipment.AttackType != "" && !combat.IsValidAttackType(def.Equipment.AttackType) { + issues = append(issues, Issue{Level: "ERROR", Type: "config", + Message: fmt.Sprintf("Item %q: invalid equipment.attack_type %q", id, def.Equipment.AttackType)}) + } + } + if def.HouseEdgePrecision != nil && *def.HouseEdgePrecision != 0 && *def.HouseEdgePrecision != 2 { + issues = append(issues, Issue{Level: "ERROR", Type: "config", + Message: fmt.Sprintf("Item %q: house_edge_precision must be 0 or 2, got %d", id, *def.HouseEdgePrecision)}) + } + if len(def.Search) > 0 { issues = append(issues, validateTriggerBlock( fmt.Sprintf("Item %q: search", id), def.Search, itemIDs, roomIndex, mobIDs, dropIDs)...) @@ -911,6 +943,16 @@ func validateCraftBlocks(s Source) []Issue { craftLabel = c.Type + "/" + c.Subtype } + // An empty ingredient list is unsatisfiable: planIngredients returns + // nil, so the craft can never produce output. + if len(c.Ingredients) == 0 { + issues = append(issues, Issue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Item %q (craft: %s): has no ingredients; the recipe can never be satisfied", item.ID, craftLabel), + }) + } + // The runtime selects the action by subtype (or type when no subtype // is set), defaulting to combine. An unknown key leaves the action // set but never advancing, so the player appears stuck. @@ -1106,6 +1148,13 @@ func validateDropTables(s Source) []Issue { } for i, d := range dt.Drops { + if d.Weight <= 0 { + issues = append(issues, Issue{ + Level: "WARN", + Type: "integrity", + Message: fmt.Sprintf("Drop table %q entry %d: weight %d is never selectable", id, i+1, d.Weight), + }) + } if d.ItemID != "" && !itemIDs[d.ItemID] { issues = append(issues, Issue{ Level: "ERROR", @@ -1314,6 +1363,21 @@ func validateFlagTriggerFiles(s Source) []Issue { if t.Condition != nil { issues = append(issues, validateCondition(rel, t.Condition, roomIndex, itemIDs)...) } + // Flag triggers fire only on Condition/Steps/Lock; item_id is dead here. + if t.ItemID != "" { + issues = append(issues, Issue{ + Level: "WARN", + Type: "trigger", + Message: fmt.Sprintf("trigger %s: item_id %q is ignored for flag triggers", rel, t.ItemID), + }) + if !itemIDs[t.ItemID] { + issues = append(issues, Issue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("trigger %s: item_id %q does not exist", rel, t.ItemID), + }) + } + } for si := range t.Steps { issues = append(issues, validateStep(fmt.Sprintf("%s: step[%d]", rel, si), &t.Steps[si], itemIDs, roomIndex, mobIDs, dropIDs)...) } |
