Lingo: Add panels mode door shuffle (#3163)

* Created panels mode door shuffle

* Added some panel door item names

* Remove RUNT TURN panel door

Not really useful.

* Fix logic with First SIX related stuff

* Add group_doors to slot data

* Fix LEVEL 2 behavior with panels mode

* Fixed unit tests

* Fixed duplicate IDs from merge

* Just regenerated new IDs

* Fixed duplication of color and door group items

* Removed unnecessary unit test option

* Fix The Seeker being achievable without entrance door

* Fix The Observant being achievable without locked panels

* Added some more panel doors

* Added Progressive Suits Area

* Lingo: Fix Basement access with THE MASTER

* Added indirect conditions for MASTER-blocked entrances

* Fixed Incomparable achievement access

* Fix STAIRS panel logic

* Fix merge error with good items

* Is this clearer?

* DREAD and TURN LEARN

* Allow a weird edge case for reduced locations

Panels mode door shuffle + grouped doors + color shuffle + pilgrimage enabled is exactly the right number of items for reduced locations. Removing color shuffle also allows for disabling pilgrimage, adding sunwarp locking, or both, with a couple of locations left over.

* Prevent small sphere one on panels mode

* Added shuffle_doors aliases for old options

* Fixed a unit test

* Updated datafile

* Tweaked requirements for reduced locations

* Added player name to OptionError messages

* Update generated.dat
This commit is contained in:
Star Rauchenberger
2024-07-26 04:53:11 -04:00
committed by GitHub
parent d030a698a6
commit cc22161644
20 changed files with 1274 additions and 150 deletions

View File

@@ -73,6 +73,22 @@ if old_generated.include? "door_groups" then
end
end
end
if old_generated.include? "panel_doors" then
old_generated["panel_doors"].each do |room, panel_doors|
panel_doors.each do |name, id|
if id >= next_item_id then
next_item_id = id + 1
end
end
end
end
if old_generated.include? "panel_groups" then
old_generated["panel_groups"].each do |name, id|
if id >= next_item_id then
next_item_id = id + 1
end
end
end
if old_generated.include? "progression" then
old_generated["progression"].each do |name, id|
if id >= next_item_id then
@@ -82,6 +98,7 @@ if old_generated.include? "progression" then
end
door_groups = Set[]
panel_groups = Set[]
config = YAML.load_file(configpath)
config.each do |room_name, room_data|
@@ -163,6 +180,29 @@ config.each do |room_name, room_data|
end
end
if room_data.include? "panel_doors"
room_data["panel_doors"].each do |panel_door_name, panel_door|
unless old_generated.include? "panel_doors" and old_generated["panel_doors"].include? room_name and old_generated["panel_doors"][room_name].include? panel_door_name then
old_generated["panel_doors"] ||= {}
old_generated["panel_doors"][room_name] ||= {}
old_generated["panel_doors"][room_name][panel_door_name] = next_item_id
next_item_id += 1
end
if panel_door.include? "panel_group" and not panel_groups.include? panel_door["panel_group"] then
panel_groups.add(panel_door["panel_group"])
unless old_generated.include? "panel_groups" and old_generated["panel_groups"].include? panel_door["panel_group"] then
old_generated["panel_groups"] ||= {}
old_generated["panel_groups"][panel_door["panel_group"]] = next_item_id
next_item_id += 1
end
end
end
end
if room_data.include? "progression"
room_data["progression"].each do |progression_name, pdata|
unless old_generated.include? "progression" and old_generated["progression"].include? progression_name then

View File

@@ -6,8 +6,8 @@ import sys
sys.path.append(os.path.join("worlds", "lingo"))
sys.path.append(".")
sys.path.append("..")
from datatypes import Door, DoorType, EntranceType, Painting, Panel, Progression, Room, RoomAndDoor, RoomAndPanel,\
RoomEntrance
from datatypes import Door, DoorType, EntranceType, Painting, Panel, PanelDoor, Progression, Room, RoomAndDoor,\
RoomAndPanel, RoomAndPanelDoor, RoomEntrance
import hashlib
import pickle
@@ -18,10 +18,12 @@ import Utils
ALL_ROOMS: List[Room] = []
DOORS_BY_ROOM: Dict[str, Dict[str, Door]] = {}
PANELS_BY_ROOM: Dict[str, Dict[str, Panel]] = {}
PANEL_DOORS_BY_ROOM: Dict[str, Dict[str, PanelDoor]] = {}
PAINTINGS: Dict[str, Painting] = {}
PROGRESSIVE_ITEMS: List[str] = []
PROGRESSION_BY_ROOM: Dict[str, Dict[str, Progression]] = {}
PROGRESSIVE_ITEMS: Set[str] = set()
PROGRESSIVE_DOORS_BY_ROOM: Dict[str, Dict[str, Progression]] = {}
PROGRESSIVE_PANELS_BY_ROOM: Dict[str, Dict[str, Progression]] = {}
PAINTING_ENTRANCES: int = 0
PAINTING_EXIT_ROOMS: Set[str] = set()
@@ -37,8 +39,13 @@ PANEL_LOCATION_IDS: Dict[str, Dict[str, int]] = {}
DOOR_LOCATION_IDS: Dict[str, Dict[str, int]] = {}
DOOR_ITEM_IDS: Dict[str, Dict[str, int]] = {}
DOOR_GROUP_ITEM_IDS: Dict[str, int] = {}
PANEL_DOOR_ITEM_IDS: Dict[str, Dict[str, int]] = {}
PANEL_GROUP_ITEM_IDS: Dict[str, int] = {}
PROGRESSIVE_ITEM_IDS: Dict[str, int] = {}
# This doesn't need to be stored in the datafile.
PANEL_DOOR_BY_PANEL_BY_ROOM: Dict[str, Dict[str, str]] = {}
def hash_file(path):
md5 = hashlib.md5()
@@ -53,7 +60,7 @@ def hash_file(path):
def load_static_data(ll1_path, ids_path):
global PAINTING_EXITS, SPECIAL_ITEM_IDS, PANEL_LOCATION_IDS, DOOR_LOCATION_IDS, DOOR_ITEM_IDS, \
DOOR_GROUP_ITEM_IDS, PROGRESSIVE_ITEM_IDS
DOOR_GROUP_ITEM_IDS, PROGRESSIVE_ITEM_IDS, PANEL_DOOR_ITEM_IDS, PANEL_GROUP_ITEM_IDS
# Load in all item and location IDs. These are broken up into groups based on the type of item/location.
with open(ids_path, "r") as file:
@@ -86,6 +93,17 @@ def load_static_data(ll1_path, ids_path):
for item_name, item_id in config["door_groups"].items():
DOOR_GROUP_ITEM_IDS[item_name] = item_id
if "panel_doors" in config:
for room_name, panel_doors in config["panel_doors"].items():
PANEL_DOOR_ITEM_IDS[room_name] = {}
for panel_door, item_id in panel_doors.items():
PANEL_DOOR_ITEM_IDS[room_name][panel_door] = item_id
if "panel_groups" in config:
for item_name, item_id in config["panel_groups"].items():
PANEL_GROUP_ITEM_IDS[item_name] = item_id
if "progression" in config:
for item_name, item_id in config["progression"].items():
PROGRESSIVE_ITEM_IDS[item_name] = item_id
@@ -147,6 +165,46 @@ def process_entrance(source_room, doors, room_obj):
room_obj.entrances.append(RoomEntrance(source_room, door, entrance_type))
def process_panel_door(room_name, panel_door_name, panel_door_data):
global PANEL_DOORS_BY_ROOM, PANEL_DOOR_BY_PANEL_BY_ROOM
panels: List[RoomAndPanel] = list()
for panel in panel_door_data["panels"]:
if isinstance(panel, dict):
panels.append(RoomAndPanel(panel["room"], panel["panel"]))
else:
panels.append(RoomAndPanel(room_name, panel))
for panel in panels:
PANEL_DOOR_BY_PANEL_BY_ROOM.setdefault(panel.room, {})[panel.panel] = RoomAndPanelDoor(room_name,
panel_door_name)
if "item_name" in panel_door_data:
item_name = panel_door_data["item_name"]
else:
panel_per_room = dict()
for panel in panels:
panel_room_name = room_name if panel.room is None else panel.room
panel_per_room.setdefault(panel_room_name, []).append(panel.panel)
room_strs = list()
for door_room_str, door_panels_str in panel_per_room.items():
room_strs.append(door_room_str + " - " + ", ".join(door_panels_str))
if len(panels) == 1:
item_name = f"{room_strs[0]} (Panel)"
else:
item_name = " and ".join(room_strs) + " (Panels)"
if "panel_group" in panel_door_data:
panel_group = panel_door_data["panel_group"]
else:
panel_group = None
panel_door_obj = PanelDoor(item_name, panel_group)
PANEL_DOORS_BY_ROOM[room_name][panel_door_name] = panel_door_obj
def process_panel(room_name, panel_name, panel_data):
global PANELS_BY_ROOM
@@ -227,13 +285,18 @@ def process_panel(room_name, panel_name, panel_data):
else:
non_counting = False
if room_name in PANEL_DOOR_BY_PANEL_BY_ROOM and panel_name in PANEL_DOOR_BY_PANEL_BY_ROOM[room_name]:
panel_door = PANEL_DOOR_BY_PANEL_BY_ROOM[room_name][panel_name]
else:
panel_door = None
if "location_name" in panel_data:
location_name = panel_data["location_name"]
else:
location_name = None
panel_obj = Panel(required_rooms, required_doors, required_panels, colors, check, event, exclude_reduce,
achievement, non_counting, location_name)
achievement, non_counting, panel_door, location_name)
PANELS_BY_ROOM[room_name][panel_name] = panel_obj
@@ -325,7 +388,7 @@ def process_door(room_name, door_name, door_data):
painting_ids = []
door_type = DoorType.NORMAL
if door_name.endswith(" Sunwarp"):
if room_name == "Sunwarps":
door_type = DoorType.SUNWARP
elif room_name == "Pilgrim Antechamber" and door_name == "Sun Painting":
door_type = DoorType.SUN_PAINTING
@@ -404,11 +467,11 @@ def process_sunwarp(room_name, sunwarp_data):
SUNWARP_EXITS[sunwarp_data["dots"] - 1] = room_name
def process_progression(room_name, progression_name, progression_doors):
global PROGRESSIVE_ITEMS, PROGRESSION_BY_ROOM
def process_progressive_door(room_name, progression_name, progression_doors):
global PROGRESSIVE_ITEMS, PROGRESSIVE_DOORS_BY_ROOM
# Progressive items are configured as a list of doors.
PROGRESSIVE_ITEMS.append(progression_name)
PROGRESSIVE_ITEMS.add(progression_name)
progression_index = 1
for door in progression_doors:
@@ -419,11 +482,31 @@ def process_progression(room_name, progression_name, progression_doors):
door_room = room_name
door_door = door
room_progressions = PROGRESSION_BY_ROOM.setdefault(door_room, {})
room_progressions = PROGRESSIVE_DOORS_BY_ROOM.setdefault(door_room, {})
room_progressions[door_door] = Progression(progression_name, progression_index)
progression_index += 1
def process_progressive_panel(room_name, progression_name, progression_panel_doors):
global PROGRESSIVE_ITEMS, PROGRESSIVE_PANELS_BY_ROOM
# Progressive items are configured as a list of panel doors.
PROGRESSIVE_ITEMS.add(progression_name)
progression_index = 1
for panel_door in progression_panel_doors:
if isinstance(panel_door, Dict):
panel_door_room = panel_door["room"]
panel_door_door = panel_door["panel_door"]
else:
panel_door_room = room_name
panel_door_door = panel_door
room_progressions = PROGRESSIVE_PANELS_BY_ROOM.setdefault(panel_door_room, {})
room_progressions[panel_door_door] = Progression(progression_name, progression_index)
progression_index += 1
def process_room(room_name, room_data):
global ALL_ROOMS
@@ -433,6 +516,12 @@ def process_room(room_name, room_data):
for source_room, doors in room_data["entrances"].items():
process_entrance(source_room, doors, room_obj)
if "panel_doors" in room_data:
PANEL_DOORS_BY_ROOM[room_name] = dict()
for panel_door_name, panel_door_data in room_data["panel_doors"].items():
process_panel_door(room_name, panel_door_name, panel_door_data)
if "panels" in room_data:
PANELS_BY_ROOM[room_name] = dict()
@@ -454,8 +543,11 @@ def process_room(room_name, room_data):
process_sunwarp(room_name, sunwarp_data)
if "progression" in room_data:
for progression_name, progression_doors in room_data["progression"].items():
process_progression(room_name, progression_name, progression_doors)
for progression_name, pdata in room_data["progression"].items():
if "doors" in pdata:
process_progressive_door(room_name, progression_name, pdata["doors"])
if "panel_doors" in pdata:
process_progressive_panel(room_name, progression_name, pdata["panel_doors"])
ALL_ROOMS.append(room_obj)
@@ -492,8 +584,10 @@ if __name__ == '__main__':
"ALL_ROOMS": ALL_ROOMS,
"DOORS_BY_ROOM": DOORS_BY_ROOM,
"PANELS_BY_ROOM": PANELS_BY_ROOM,
"PANEL_DOORS_BY_ROOM": PANEL_DOORS_BY_ROOM,
"PROGRESSIVE_ITEMS": PROGRESSIVE_ITEMS,
"PROGRESSION_BY_ROOM": PROGRESSION_BY_ROOM,
"PROGRESSIVE_DOORS_BY_ROOM": PROGRESSIVE_DOORS_BY_ROOM,
"PROGRESSIVE_PANELS_BY_ROOM": PROGRESSIVE_PANELS_BY_ROOM,
"PAINTING_ENTRANCES": PAINTING_ENTRANCES,
"PAINTING_EXIT_ROOMS": PAINTING_EXIT_ROOMS,
"PAINTING_EXITS": PAINTING_EXITS,
@@ -506,6 +600,8 @@ if __name__ == '__main__':
"DOOR_LOCATION_IDS": DOOR_LOCATION_IDS,
"DOOR_ITEM_IDS": DOOR_ITEM_IDS,
"DOOR_GROUP_ITEM_IDS": DOOR_GROUP_ITEM_IDS,
"PANEL_DOOR_ITEM_IDS": PANEL_DOOR_ITEM_IDS,
"PANEL_GROUP_ITEM_IDS": PANEL_GROUP_ITEM_IDS,
"PROGRESSIVE_ITEM_IDS": PROGRESSIVE_ITEM_IDS,
}

View File

@@ -33,19 +33,23 @@ end
configured_rooms = Set["Menu"]
configured_doors = Set[]
configured_panels = Set[]
configured_panel_doors = Set[]
mentioned_rooms = Set[]
mentioned_doors = Set[]
mentioned_panels = Set[]
mentioned_panel_doors = Set[]
mentioned_sunwarp_entrances = Set[]
mentioned_sunwarp_exits = Set[]
mentioned_paintings = Set[]
door_groups = {}
panel_groups = {}
directives = Set["entrances", "panels", "doors", "paintings", "sunwarps", "progression"]
directives = Set["entrances", "panels", "doors", "panel_doors", "paintings", "sunwarps", "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", "location_name"]
door_directives = Set["id", "painting_id", "panels", "item_name", "item_group", "location_name", "skip_location", "skip_item", "door_group", "include_reduce", "event", "warp_id"]
panel_door_directives = Set["panels", "item_name", "panel_group"]
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
@@ -253,6 +257,43 @@ config.each do |room_name, room|
end
end
(room["panel_doors"] || {}).each do |panel_door_name, panel_door|
configured_panel_doors.add("#{room_name} - #{panel_door_name}")
if panel_door.include?("panels")
panel_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
else
puts "#{room_name} - #{panel_door_name} :::: Missing panels field"
end
if panel_door.include?("panel_group")
panel_groups[panel_door["panel_group"]] ||= 0
panel_groups[panel_door["panel_group"]] += 1
end
bad_subdirectives = []
panel_door.keys.each do |key|
unless panel_door_directives.include?(key) then
bad_subdirectives << key
end
end
unless bad_subdirectives.empty? then
puts "#{room_name} - #{panel_door_name} :::: Panel door has the following invalid subdirectives: #{bad_subdirectives.join(", ")}"
end
unless ids.include?("panel_doors") and ids["panel_doors"].include?(room_name) and ids["panel_doors"][room_name].include?(panel_door_name)
puts "#{room_name} - #{panel_door_name} :::: Panel door is missing an item ID"
end
end
(room["paintings"] || []).each do |painting|
if painting.include?("id") and painting["id"].kind_of? String then
unless paintings.include? painting["id"] then
@@ -327,12 +368,24 @@ config.each do |room_name, room|
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}")
(room["progression"] || {}).each do |progression_name, pdata|
if pdata.include? "doors" then
pdata["doors"].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
end
if pdata.include? "panel_doors" then
pdata["panel_doors"].each do |panel_door|
if panel_door.kind_of? Hash then
mentioned_panel_doors.add("#{panel_door["room"]} - #{panel_door["panel_door"]}")
else
mentioned_panel_doors.add("#{room_name} - #{panel_door}")
end
end
end
@@ -344,17 +397,22 @@ 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
puts "The following 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
puts "The following 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
puts "The following doors are mentioned but do not exist: " + errored_doors.to_s
end
errored_panel_doors = mentioned_panel_doors - configured_panel_doors
unless errored_panel_doors.empty? then
puts "The following panel doors are mentioned but do not exist: " + errored_panel_doors.to_s
end
door_groups.each do |group,num|
@@ -367,6 +425,16 @@ door_groups.each do |group,num|
end
end
panel_groups.each do |group,num|
if num == 1 then
puts "Panel group \"#{group}\" only has one panel in it"
end
unless ids.include?("panel_groups") and ids["panel_groups"].include?(group)
puts "#{group} :::: Panel group is missing an item ID"
end
end
slashed_rooms = configured_rooms.select do |room|
room.include? "/"
end