Files
Grinch-AP/worlds/lingo/utils/validate_config.rb
Star Rauchenberger 2c38b9fd51 Lingo: Various item/location renames (#2746)
## What is this fixing or adding?
- Roof MASTERY panels are now technically in individual regions with more descriptive names, so they can be displayed better on the tracker.
- Orange Tower Seventh Floor - Mastery has been renamed to simply Mastery.
- The Optimistic is its own region now.
- The misnamed CEILING in Room Room has been fixed.
- The misnamed CHEESE in Challenge Room has been fixed.
- The misnamed SOUND in Outside the Bold has been fixed.
- "The Bearer - Shortcut to The Bold" is now "The Bearer - Entrance".
- HUB ROOM - NEAR, FAR and the Warts Straw and Leaf Feel Areas have now been semantically combined into the "Symmetry Room". They are still logically three separate regions.
- The FACTS chain in Challenge Room has been reindexed, and the full chain panel is now indicated as such.
- The Room Room floors have been reindexed.
- Panels in The Observant are now named by their questions, not answers.
- Added a (1) subscript to several panels in Orange Tower Fourth Floor, Outside The Initiated, and The Seeker.

The validate_config.rb script has also been updated to check that all items and locations have an ID.

This change should not impact generation logic at all. It is just changing item and location names.
2024-02-15 21:03:10 +01:00

357 lines
11 KiB
Ruby

# Script to validate a level config file. This checks that the names used within
# the file are consistent. It also checks that the panel and door IDs mentioned
# all exist in the map file.
#
# Usage: validate_config.rb [config file] [map file]
require 'set'
require 'yaml'
configpath = ARGV[0]
idspath = ARGV[1]
mappath = ARGV[2]
panels = Set["Countdown Panels/Panel_1234567890_wanderlust"]
doors = Set["Naps Room Doors/Door_hider_new1", "Tower Room Area Doors/Door_wanderer_entrance"]
paintings = Set[]
File.readlines(mappath).each do |line|
line.match(/node name=\"(.*)\" parent=\"Panels\/(.*)\" instance/) do |m|
panels.add(m[2] + "/" + m[1])
end
line.match(/node name=\"(.*)\" parent=\"Doors\/(.*)\" instance/) do |m|
doors.add(m[2] + "/" + m[1])
end
line.match(/node name=\"(.*)\" parent=\"Decorations\/Paintings\" instance/) do |m|
paintings.add(m[1])
end
line.match(/node name=\"(.*)\" parent=\"Decorations\/EndPanel\" instance/) do |m|
panels.add("EndPanel/" + m[1])
end
end
configured_rooms = Set["Menu"]
configured_doors = Set[]
configured_panels = Set[]
mentioned_rooms = Set[]
mentioned_doors = Set[]
mentioned_panels = Set[]
door_groups = {}
directives = Set["entrances", "panels", "doors", "paintings", "progression"]
panel_directives = Set["id", "required_room", "required_door", "required_panel", "colors", "check", "exclude_reduce", "tag", "link", "subtag", "achievement", "copy_to_sign", "non_counting", "hunt"]
door_directives = Set["id", "painting_id", "panels", "item_name", "location_name", "skip_location", "skip_item", "group", "include_reduce", "junk_item", "event"]
painting_directives = Set["id", "enter_only", "exit_only", "orientation", "required_door", "required", "required_when_no_doors", "move", "req_blocked", "req_blocked_when_no_doors"]
non_counting = 0
ids = YAML.load_file(idspath)
config = YAML.load_file(configpath)
config.each do |room_name, room|
configured_rooms.add(room_name)
used_directives = Set[]
room.each_key do |key|
used_directives.add(key)
end
diff_directives = used_directives - directives
unless diff_directives.empty? then
puts("#{room_name} has the following invalid top-level directives: #{diff_directives.to_s}")
end
(room["entrances"] || {}).each do |source_room, entrance|
mentioned_rooms.add(source_room)
entrances = []
if entrance.kind_of? Hash
if entrance.keys() != ["painting"] then
entrances = [entrance]
end
elsif entrance.kind_of? Array
entrances = entrance
end
entrances.each do |e|
entrance_room = e.include?("room") ? e["room"] : room_name
mentioned_rooms.add(entrance_room)
mentioned_doors.add(entrance_room + " - " + e["door"])
end
end
(room["panels"] || {}).each do |panel_name, panel|
unless panel_name.kind_of? String then
puts "#{room_name} has an invalid panel name"
end
configured_panels.add(room_name + " - " + panel_name)
if panel.include?("id")
panel_ids = []
if panel["id"].kind_of? Array
panel_ids = panel["id"]
else
panel_ids = [panel["id"]]
end
panel_ids.each do |panel_id|
unless panels.include? panel_id then
puts "#{room_name} - #{panel_name} :::: Invalid Panel ID #{panel_id}"
end
end
else
puts "#{room_name} - #{panel_name} :::: Panel is missing an ID"
end
if panel.include?("required_room")
required_rooms = []
if panel["required_room"].kind_of? Array
required_rooms = panel["required_room"]
else
required_rooms = [panel["required_room"]]
end
required_rooms.each do |required_room|
mentioned_rooms.add(required_room)
end
end
if panel.include?("required_door")
required_doors = []
if panel["required_door"].kind_of? Array
required_doors = panel["required_door"]
else
required_doors = [panel["required_door"]]
end
required_doors.each do |required_door|
other_room = required_door.include?("room") ? required_door["room"] : room_name
mentioned_rooms.add(other_room)
mentioned_doors.add("#{other_room} - #{required_door["door"]}")
end
end
if panel.include?("required_panel")
required_panels = []
if panel["required_panel"].kind_of? Array
required_panels = panel["required_panel"]
else
required_panels = [panel["required_panel"]]
end
required_panels.each do |required_panel|
other_room = required_panel.include?("room") ? required_panel["room"] : room_name
mentioned_rooms.add(other_room)
mentioned_panels.add("#{other_room} - #{required_panel["panel"]}")
end
end
unless panel.include?("tag") then
puts "#{room_name} - #{panel_name} :::: Panel is missing a tag"
end
if panel.include?("non_counting") then
non_counting += 1
end
bad_subdirectives = []
panel.keys.each do |key|
unless panel_directives.include?(key) then
bad_subdirectives << key
end
end
unless bad_subdirectives.empty? then
puts "#{room_name} - #{panel_name} :::: Panel has the following invalid subdirectives: #{bad_subdirectives.join(", ")}"
end
unless ids.include?("panels") and ids["panels"].include?(room_name) and ids["panels"][room_name].include?(panel_name)
puts "#{room_name} - #{panel_name} :::: Panel is missing a location ID"
end
end
(room["doors"] || {}).each do |door_name, door|
configured_doors.add("#{room_name} - #{door_name}")
if door.include?("id")
door_ids = []
if door["id"].kind_of? Array
door_ids = door["id"]
else
door_ids = [door["id"]]
end
door_ids.each do |door_id|
unless doors.include? door_id then
puts "#{room_name} - #{door_name} :::: Invalid Door ID #{door_id}"
end
end
end
if door.include?("painting_id")
painting_ids = []
if door["painting_id"].kind_of? Array
painting_ids = door["painting_id"]
else
painting_ids = [door["painting_id"]]
end
painting_ids.each do |painting_id|
unless paintings.include? painting_id then
puts "#{room_name} - #{door_name} :::: Invalid Painting ID #{painting_id}"
end
end
end
if not door.include?("id") and not door.include?("painting_id") and not door["skip_item"] and not door["event"] then
puts "#{room_name} - #{door_name} :::: Should be marked skip_item or event if there are no doors or paintings"
end
if door.include?("panels")
door["panels"].each do |panel|
if panel.kind_of? Hash then
other_room = panel.include?("room") ? panel["room"] : room_name
mentioned_panels.add("#{other_room} - #{panel["panel"]}")
else
other_room = panel.include?("room") ? panel["room"] : room_name
mentioned_panels.add("#{room_name} - #{panel}")
end
end
elsif not door["skip_location"]
puts "#{room_name} - #{door_name} :::: Should be marked skip_location if there are no panels"
end
if door.include?("group")
door_groups[door["group"]] ||= 0
door_groups[door["group"]] += 1
end
bad_subdirectives = []
door.keys.each do |key|
unless door_directives.include?(key) then
bad_subdirectives << key
end
end
unless bad_subdirectives.empty? then
puts "#{room_name} - #{door_name} :::: Door has the following invalid subdirectives: #{bad_subdirectives.join(", ")}"
end
unless door["skip_item"] or door["event"]
unless ids.include?("doors") and ids["doors"].include?(room_name) and ids["doors"][room_name].include?(door_name) and ids["doors"][room_name][door_name].include?("item")
puts "#{room_name} - #{door_name} :::: Door is missing an item ID"
end
end
unless door["skip_location"] or door["event"]
unless ids.include?("doors") and ids["doors"].include?(room_name) and ids["doors"][room_name].include?(door_name) and ids["doors"][room_name][door_name].include?("location")
puts "#{room_name} - #{door_name} :::: Door is missing a location ID"
end
end
end
(room["paintings"] || []).each do |painting|
if painting.include?("id") and painting["id"].kind_of? String then
unless paintings.include? painting["id"] then
puts "#{room_name} :::: Invalid Painting ID #{painting["id"]}"
end
else
puts "#{room_name} :::: Painting is missing an ID"
end
if painting["disable"] then
# We're good.
next
end
if painting.include?("orientation") then
unless ["north", "south", "east", "west"].include? painting["orientation"] then
puts "#{room_name} - #{painting["id"] || "painting"} :::: Invalid orientation #{painting["orientation"]}"
end
else
puts "#{room_name} :::: Painting is missing an orientation"
end
if painting.include?("required_door")
other_room = painting["required_door"].include?("room") ? painting["required_door"]["room"] : room_name
mentioned_doors.add("#{other_room} - #{painting["required_door"]["door"]}")
unless painting["enter_only"] then
puts "#{room_name} - #{painting["id"] || "painting"} :::: Should be marked enter_only if there is a required_door"
end
end
bad_subdirectives = []
painting.keys.each do |key|
unless painting_directives.include?(key) then
bad_subdirectives << key
end
end
unless bad_subdirectives.empty? then
puts "#{room_name} - #{painting["id"] || "painting"} :::: Painting has the following invalid subdirectives: #{bad_subdirectives.join(", ")}"
end
end
(room["progression"] || {}).each do |progression_name, door_list|
door_list.each do |door|
if door.kind_of? Hash then
mentioned_doors.add("#{door["room"]} - #{door["door"]}")
else
mentioned_doors.add("#{room_name} - #{door}")
end
end
unless ids.include?("progression") and ids["progression"].include?(progression_name)
puts "#{room_name} - #{progression_name} :::: Progression is missing an item ID"
end
end
end
errored_rooms = mentioned_rooms - configured_rooms
unless errored_rooms.empty? then
puts "The folloring rooms are mentioned but do not exist: " + errored_rooms.to_s
end
errored_panels = mentioned_panels - configured_panels
unless errored_panels.empty? then
puts "The folloring panels are mentioned but do not exist: " + errored_panels.to_s
end
errored_doors = mentioned_doors - configured_doors
unless errored_doors.empty? then
puts "The folloring doors are mentioned but do not exist: " + errored_doors.to_s
end
door_groups.each do |group,num|
if num == 1 then
puts "Door group \"#{group}\" only has one door in it"
end
unless ids.include?("door_groups") and ids["door_groups"].include?(group)
puts "#{group} :::: Door group is missing an item ID"
end
end
slashed_rooms = configured_rooms.select do |room|
room.include? "/"
end
unless slashed_rooms.empty? then
puts "The following rooms have slashes in their names: " + slashed_rooms.to_s
end
slashed_panels = configured_panels.select do |panel|
panel.include? "/"
end
unless slashed_panels.empty? then
puts "The following panels have slashes in their names: " + slashed_panels.to_s
end
slashed_doors = configured_doors.select do |door|
door.include? "/"
end
unless slashed_doors.empty? then
puts "The following doors have slashes in their names: " + slashed_doors.to_s
end
puts "#{configured_panels.size} panels (#{non_counting} non counting)"