about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md38
-rw-r--r--apworld/__init__.py13
-rw-r--r--apworld/client/gamedata.gd8
-rw-r--r--apworld/client/manager.gd31
-rw-r--r--apworld/client/maps/control_center.gd55
-rw-r--r--apworld/client/player.gd40
-rw-r--r--apworld/client/rteMenu.gd55
-rw-r--r--apworld/items.py5
-rw-r--r--apworld/locations.py27
-rw-r--r--apworld/options.py32
-rw-r--r--apworld/player_logic.py21
-rw-r--r--apworld/regions.py11
-rw-r--r--data/door_groups.txtpb14
-rw-r--r--data/ids.yaml1
-rw-r--r--data/maps/control_center/connections.txtpb1
-rw-r--r--data/maps/control_center/doors.txtpb2
-rw-r--r--data/maps/four_rooms/metadata.txtpb2
-rw-r--r--data/maps/icarus/metadata.txtpb2
-rw-r--r--data/maps/the_advanced/metadata.txtpb2
-rw-r--r--data/maps/the_ancient/metadata.txtpb2
-rw-r--r--data/maps/the_bearer/metadata.txtpb2
-rw-r--r--data/maps/the_between/metadata.txtpb2
-rw-r--r--data/maps/the_butterfly/metadata.txtpb2
-rw-r--r--data/maps/the_charismatic/metadata.txtpb2
-rw-r--r--data/maps/the_colorful/metadata.txtpb2
-rw-r--r--data/maps/the_congruent/metadata.txtpb2
-rw-r--r--data/maps/the_crystalline/metadata.txtpb2
-rw-r--r--data/maps/the_darkroom/metadata.txtpb2
-rw-r--r--data/maps/the_digital/metadata.txtpb2
-rw-r--r--data/maps/the_double_sided/metadata.txtpb2
-rw-r--r--data/maps/the_extravagant/metadata.txtpb2
-rw-r--r--data/maps/the_fuzzy/metadata.txtpb2
-rw-r--r--data/maps/the_graveyard/metadata.txtpb2
-rw-r--r--data/maps/the_great/metadata.txtpb2
-rw-r--r--data/maps/the_hive/metadata.txtpb2
-rw-r--r--data/maps/the_impressive/metadata.txtpb2
-rw-r--r--data/maps/the_invisible/metadata.txtpb2
-rw-r--r--data/maps/the_jubilant/metadata.txtpb2
-rw-r--r--data/maps/the_keen/metadata.txtpb2
-rw-r--r--data/maps/the_liberated/metadata.txtpb2
-rw-r--r--data/maps/the_linear/metadata.txtpb2
-rw-r--r--data/maps/the_lionized/metadata.txtpb2
-rw-r--r--data/maps/the_literate/metadata.txtpb2
-rw-r--r--data/maps/the_lively/metadata.txtpb2
-rw-r--r--data/maps/the_nuanced/metadata.txtpb2
-rw-r--r--data/maps/the_orb/metadata.txtpb2
-rw-r--r--data/maps/the_owl/metadata.txtpb2
-rw-r--r--data/maps/the_parthenon/metadata.txtpb2
-rw-r--r--data/maps/the_partial/metadata.txtpb2
-rw-r--r--data/maps/the_perceptive/metadata.txtpb2
-rw-r--r--data/maps/the_quiet/metadata.txtpb2
-rw-r--r--data/maps/the_repetitive/metadata.txtpb2
-rw-r--r--data/maps/the_revitalized/metadata.txtpb2
-rw-r--r--data/maps/the_shop/metadata.txtpb2
-rw-r--r--data/maps/the_sirenic/metadata.txtpb2
-rw-r--r--data/maps/the_stellar/metadata.txtpb2
-rw-r--r--data/maps/the_stormy/metadata.txtpb2
-rw-r--r--data/maps/the_sturdy/metadata.txtpb2
-rw-r--r--data/maps/the_sun_temple/metadata.txtpb2
-rw-r--r--data/maps/the_sweet/metadata.txtpb2
-rw-r--r--data/maps/the_symbolic/metadata.txtpb2
-rw-r--r--data/maps/the_talented/metadata.txtpb2
-rw-r--r--data/maps/the_tenacious/metadata.txtpb2
-rw-r--r--data/maps/the_three_doors/metadata.txtpb2
-rw-r--r--data/maps/the_tower/metadata.txtpb2
-rw-r--r--data/maps/the_tree/metadata.txtpb2
-rw-r--r--data/maps/the_unkempt/metadata.txtpb2
-rw-r--r--data/maps/the_unyielding/metadata.txtpb2
-rw-r--r--data/maps/the_wise/metadata.txtpb2
-rw-r--r--data/maps/the_wondrous/metadata.txtpb2
-rw-r--r--data/maps/the_words/metadata.txtpb2
-rw-r--r--data/metadata.txtpb6
-rw-r--r--proto/data.proto3
-rw-r--r--proto/human.proto6
-rw-r--r--tools/datapacker/main.cpp10
75 files changed, 476 insertions, 13 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 3740ed5..0433d83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md
@@ -1,5 +1,43 @@
1# lingo2-archipelago Releases 1# lingo2-archipelago Releases
2 2
3## v9.0.0 - 2026-02-07
4
5- Added "Shuffle Fast Travel" option. This allows you to randomize the
6 destinations of the fast travel buttons on the pause menu to almost any map
7 (except for The Entry, which is always the center button).
8- Added "Fast Travel Access" option. By default, fast travel is unlocked by
9 entering the destination area manually. You can instead set to have all fast
10 travel destinations unlocked from the start, or have them locked behind items
11 (apart from The Entry).
12- Added "Restrict Letter Placements" option. When enabled, letter items will
13 only be placed in your local world, in letter locations. This only has an
14 effect when Shuffle Letters is set to Item Cyan or Progressive. This is
15 experimental, and may slow down generation.
16- The values of the Endings Requirement and Masteries Requirement options are
17 now shown in the Control Center, as well as how many endings and masteries you
18 currently have.
19- Previously, vanilla doors logic expected you to have to solve every panel in
20 the Daedalus Computer Room in order to use the back exit door. This has been
21 fixed to only require solving one panel.
22- Previously, shuffled doors + shuffled worldports logic expected you to be able
23 to enter Control Center from the Perceptive Entrance without the door item by
24 solving the PART panel (as you would in vanilla doors). This has been fixed so
25 that the door item is required in both directions.
26
27Compatibility notes:
28
29- The change to the door in the Control Center required creating a new item with
30 a new ID, which is not present in worlds generated on older versions of the
31 apworld. Therefore, if you have an older world using door shuffle, you may not
32 be able to access the checks in the Perceptive Entrance or the worldport (if
33 worldports are shuffled).
34
35Download:
36[lingo2.apworld](https://files.fourisland.com/releases/lingo2-archipelago/apworld/v9.0.0/lingo2.apworld)<br/>
37Template YAML:
38[Lingo 2.yaml](https://files.fourisland.com/releases/lingo2-archipelago/apworld/v9.0.0/Lingo%202.yaml)<br/>
39Source: [v9.0.0](https://code.fourisland.com/lingo2-archipelago/tag/?h=v9.0.0)
40
3## v8.1.1 - 2026-02-05 41## v8.1.1 - 2026-02-05
4 42
5- Fixed issue in Daedalus Only mode where the Lavender Cubes and Rainbow Rooms 43- Fixed issue in Daedalus Only mode where the Lavender Cubes and Rainbow Rooms
diff --git a/apworld/__init__.py b/apworld/__init__.py index 42350bc..6b5338e 100644 --- a/apworld/__init__.py +++ b/apworld/__init__.py
@@ -7,7 +7,7 @@ from BaseClasses import ItemClassification, Item, Tutorial
7from Options import OptionError 7from Options import OptionError
8from settings import Group, UserFilePath 8from settings import Group, UserFilePath
9from worlds.AutoWorld import WebWorld, World 9from worlds.AutoWorld import WebWorld, World
10from .items import Lingo2Item, ANTI_COLLECTABLE_TRAPS 10from .items import Lingo2Item, ANTI_COLLECTABLE_TRAPS, ALL_LETTERS_UPPER
11from .options import Lingo2Options 11from .options import Lingo2Options
12from .player_logic import Lingo2PlayerLogic 12from .player_logic import Lingo2PlayerLogic
13from .regions import create_regions, shuffle_entrances, connect_ports_from_ut 13from .regions import create_regions, shuffle_entrances, connect_ports_from_ut
@@ -70,6 +70,9 @@ class Lingo2World(World):
70 self.player_logic = Lingo2PlayerLogic(self) 70 self.player_logic = Lingo2PlayerLogic(self)
71 self.port_pairings = {} 71 self.port_pairings = {}
72 72
73 if self.options.restrict_letter_placements:
74 self.options.local_items.value |= set(ALL_LETTERS_UPPER)
75
73 def create_regions(self): 76 def create_regions(self):
74 if hasattr(self.multiworld, "re_gen_passthrough") and "Lingo 2" in self.multiworld.re_gen_passthrough: 77 if hasattr(self.multiworld, "re_gen_passthrough") and "Lingo 2" in self.multiworld.re_gen_passthrough:
75 self.player_logic.rte_mapping = [self.world.static_logic.map_id_by_name[map_name] 78 self.player_logic.rte_mapping = [self.world.static_logic.map_id_by_name[map_name]
@@ -128,11 +131,14 @@ class Lingo2World(World):
128 self.push_precollected(self.create_item(name)) 131 self.push_precollected(self.create_item(name))
129 132
130 def create_item(self, name: str) -> Item: 133 def create_item(self, name: str) -> Item:
131 return Lingo2Item(name, ItemClassification.filler if name == self.get_filler_item_name() else 134 item = Lingo2Item(name, ItemClassification.filler if name == self.get_filler_item_name() else
132 ItemClassification.trap if name in ANTI_COLLECTABLE_TRAPS else 135 ItemClassification.trap if name in ANTI_COLLECTABLE_TRAPS else
133 ItemClassification.progression, 136 ItemClassification.progression,
134 self.item_name_to_id.get(name), self.player) 137 self.item_name_to_id.get(name), self.player)
135 138
139 item.is_letter = (name in ALL_LETTERS_UPPER)
140 return item
141
136 def set_rules(self): 142 def set_rules(self):
137 self.multiworld.completion_condition[self.player] = lambda state: state.has("Victory", self.player) 143 self.multiworld.completion_condition[self.player] = lambda state: state.has("Victory", self.player)
138 144
@@ -151,6 +157,7 @@ class Lingo2World(World):
151 "shuffle_doors", 157 "shuffle_doors",
152 "shuffle_gallery_paintings", 158 "shuffle_gallery_paintings",
153 "shuffle_letters", 159 "shuffle_letters",
160 "shuffle_music",
154 "shuffle_symbols", 161 "shuffle_symbols",
155 "shuffle_worldports", 162 "shuffle_worldports",
156 "strict_cyan_ending", 163 "strict_cyan_ending",
@@ -160,7 +167,9 @@ class Lingo2World(World):
160 167
161 slot_data: dict[str, object] = { 168 slot_data: dict[str, object] = {
162 **self.options.as_dict(*slot_options), 169 **self.options.as_dict(*slot_options),
170 "custom_mint_ending": self.player_logic.custom_mint_ending or "",
163 "rte": [self.static_logic.objects.maps[map_id].name for map_id in self.player_logic.rte_mapping], 171 "rte": [self.static_logic.objects.maps[map_id].name for map_id in self.player_logic.rte_mapping],
172 "seed": self.random.randint(0, 1000000),
164 "version": self.static_logic.get_data_version(), 173 "version": self.static_logic.get_data_version(),
165 } 174 }
166 175
diff --git a/apworld/client/gamedata.gd b/apworld/client/gamedata.gd index d7e3136..373f981 100644 --- a/apworld/client/gamedata.gd +++ b/apworld/client/gamedata.gd
@@ -16,6 +16,7 @@ var anti_trap_ids = {}
16var location_name_by_id = {} 16var location_name_by_id = {}
17var ending_display_name_by_name = {} 17var ending_display_name_by_name = {}
18var port_id_by_ap_id = {} 18var port_id_by_ap_id = {}
19var map_id_by_rte_ap_id = {}
19 20
20var kSYMBOL_ITEMS 21var kSYMBOL_ITEMS
21 22
@@ -57,6 +58,9 @@ func load(data_bytes):
57 for map in objects.get_maps(): 58 for map in objects.get_maps():
58 map_id_by_name[map.get_name()] = map.get_id() 59 map_id_by_name[map.get_name()] = map.get_id()
59 60
61 if map.has_rte_ap_id():
62 map_id_by_rte_ap_id[map.get_rte_ap_id()] = map.get_id()
63
60 for door in objects.get_doors(): 64 for door in objects.get_doors():
61 var map = objects.get_maps()[door.get_map_id()] 65 var map = objects.get_maps()[door.get_map_id()]
62 66
@@ -300,3 +304,7 @@ func _get_keyholder_location_name(keyholder):
300 "%s - %s Keyholder" 304 "%s - %s Keyholder"
301 % [_get_room_object_location_prefix(keyholder), keyholder.get_key().to_upper()] 305 % [_get_room_object_location_prefix(keyholder), keyholder.get_key().to_upper()]
302 ) 306 )
307
308
309func vec3d_to_vector3(input) -> Vector3:
310 return Vector3(input.get_x(), input.get_y(), input.get_z())
diff --git a/apworld/client/manager.gd b/apworld/client/manager.gd index 1e0b549..f10a0b7 100644 --- a/apworld/client/manager.gd +++ b/apworld/client/manager.gd
@@ -46,6 +46,10 @@ const kCYAN_DOOR_BEHAVIOR_H2 = 0
46const kCYAN_DOOR_BEHAVIOR_DOUBLE_LETTER = 1 46const kCYAN_DOOR_BEHAVIOR_DOUBLE_LETTER = 1
47const kCYAN_DOOR_BEHAVIOR_ITEM = 2 47const kCYAN_DOOR_BEHAVIOR_ITEM = 2
48 48
49const kFAST_TRAVEL_ACCESS_VANILLA = 0
50const kFAST_TRAVEL_ACCESS_UNLOCKED = 1
51const kFAST_TRAVEL_ACCESS_ITEMS = 2
52
49const kEndingNameByVictoryValue = { 53const kEndingNameByVictoryValue = {
50 0: "GRAY", 54 0: "GRAY",
51 1: "PURPLE", 55 1: "PURPLE",
@@ -63,21 +67,26 @@ const kEndingNameByVictoryValue = {
63} 67}
64 68
65var apworld_version = [0, 0, 0] 69var apworld_version = [0, 0, 0]
70var custom_mint_ending = ""
66var cyan_door_behavior = kCYAN_DOOR_BEHAVIOR_H2 71var cyan_door_behavior = kCYAN_DOOR_BEHAVIOR_H2
67var daedalus_only = false 72var daedalus_only = false
68var daedalus_roof_access = false 73var daedalus_roof_access = false
69var enable_gift_maps = [] 74var enable_gift_maps = []
70var enable_icarus = false 75var enable_icarus = false
71var endings_requirement = 0 76var endings_requirement = 0
77var fast_travel_access = 0
72var keyholder_sanity = false 78var keyholder_sanity = false
73var masteries_requirement = 0 79var masteries_requirement = 0
80var music_mapping = {}
74var port_pairings = {} 81var port_pairings = {}
82var rte_mapping = []
75var shuffle_control_center_colors = false 83var shuffle_control_center_colors = false
76var shuffle_doors = false 84var shuffle_doors = false
77var shuffle_gallery_paintings = false 85var shuffle_gallery_paintings = false
78var shuffle_letters = kSHUFFLE_LETTERS_VANILLA 86var shuffle_letters = kSHUFFLE_LETTERS_VANILLA
79var shuffle_symbols = false 87var shuffle_symbols = false
80var shuffle_worldports = false 88var shuffle_worldports = false
89var slot_rng = null
81var strict_cyan_ending = false 90var strict_cyan_ending = false
82var strict_purple_ending = false 91var strict_purple_ending = false
83var victory_condition = -1 92var victory_condition = -1
@@ -269,6 +278,13 @@ func _process_item(item, amount):
269 if item_id == gamedata.objects.get_special_ids()["Numbers"] and global.map == "the_fuzzy": 278 if item_id == gamedata.objects.get_special_ids()["Numbers"] and global.map == "the_fuzzy":
270 global.allow_numbers = true 279 global.allow_numbers = true
271 280
281 if gamedata.map_id_by_rte_ap_id.has(item_id):
282 var rteInner = get_tree().get_root().get_node_or_null(
283 "scene/player/pause_menu/menu/return/rteInner"
284 )
285 if rteInner != null:
286 rteInner.refreshButtons()
287
272 # Show a message about the item if it's new. 288 # Show a message about the item if it's new.
273 if int(item["index"]) > _last_new_item: 289 if int(item["index"]) > _last_new_item:
274 _last_new_item = int(item["index"]) 290 _last_new_item = int(item["index"])
@@ -463,12 +479,14 @@ func _client_connected(slot_data):
463 _last_new_item = localdata[0] 479 _last_new_item = localdata[0]
464 480
465 # Read slot data. 481 # Read slot data.
482 custom_mint_ending = slot_data.get("custom_mint_ending", "")
466 cyan_door_behavior = int(slot_data.get("cyan_door_behavior", 0)) 483 cyan_door_behavior = int(slot_data.get("cyan_door_behavior", 0))
467 daedalus_only = bool(slot_data.get("daedalus_only", false)) 484 daedalus_only = bool(slot_data.get("daedalus_only", false))
468 daedalus_roof_access = bool(slot_data.get("daedalus_roof_access", false)) 485 daedalus_roof_access = bool(slot_data.get("daedalus_roof_access", false))
469 enable_gift_maps = slot_data.get("enable_gift_maps", []) 486 enable_gift_maps = slot_data.get("enable_gift_maps", [])
470 enable_icarus = bool(slot_data.get("enable_icarus", false)) 487 enable_icarus = bool(slot_data.get("enable_icarus", false))
471 endings_requirement = int(slot_data.get("endings_requirement", 0)) 488 endings_requirement = int(slot_data.get("endings_requirement", 0))
489 fast_travel_access = int(slot_data.get("fast_travel_access", 0))
472 keyholder_sanity = bool(slot_data.get("keyholder_sanity", false)) 490 keyholder_sanity = bool(slot_data.get("keyholder_sanity", false))
473 masteries_requirement = int(slot_data.get("masteries_requirement", 0)) 491 masteries_requirement = int(slot_data.get("masteries_requirement", 0))
474 shuffle_control_center_colors = bool(slot_data.get("shuffle_control_center_colors", false)) 492 shuffle_control_center_colors = bool(slot_data.get("shuffle_control_center_colors", false))
@@ -496,6 +514,19 @@ func _client_connected(slot_data):
496 raw_pp[p1] 514 raw_pp[p1]
497 )] 515 )]
498 516
517 rte_mapping.clear()
518 if slot_data.has("rte"):
519 rte_mapping = slot_data.get("rte")
520
521 slot_rng = RandomNumberGenerator.new()
522 slot_rng.seed = int(slot_data.get("seed", 0))
523
524 music_mapping.clear()
525 if bool(slot_data.get("shuffle_music", false)):
526 for map_name in global.reserved_scenes:
527 var track_index = slot_rng.randi_range(0, musicPlayer.all_tracks.size() - 1)
528 music_mapping[map_name] = musicPlayer.all_tracks.keys()[track_index]
529
499 # Set up item locks. 530 # Set up item locks.
500 _item_locks = {} 531 _item_locks = {}
501 532
diff --git a/apworld/client/maps/control_center.gd b/apworld/client/maps/control_center.gd index fadfed9..8e919ab 100644 --- a/apworld/client/maps/control_center.gd +++ b/apworld/client/maps/control_center.gd
@@ -74,6 +74,61 @@ func on_map_load(root):
74 old_door.queue_free() 74 old_door.queue_free()
75 root.get_node("/root/scene/Components/Doors").add_child.call_deferred(new_door) 75 root.get_node("/root/scene/Components/Doors").add_child.call_deferred(new_door)
76 76
77 # Display White Ending requirements.
78 var ending_count = 0
79 var mastery_count = 0
80 for key in unlocks.data:
81 if unlocks.data[key] == "unlocked":
82 if key.ends_with("_ending") and key != "free_ending":
83 ending_count += 1
84 elif key.ends_with("_mastery"):
85 mastery_count += 1
86
87 var sign_prefab = preload("res://objects/nodes/sign.tscn")
88 var sign1 = sign_prefab.instantiate()
89 sign1.position = Vector3(87.5, 5, -42.01)
90 sign1.text = "Endings: %d/%d" % [ending_count, ap.endings_requirement]
91 root.get_node("/root/scene").add_child.call_deferred(sign1)
92
93 var sign2 = sign_prefab.instantiate()
94 sign2.position = Vector3(87.5, 5, -15.99)
95 sign2.rotation_degrees.y = 180
96 sign2.text = "Masteries: %d/%d" % [mastery_count, ap.masteries_requirement]
97 root.get_node("/root/scene").add_child.call_deferred(sign2)
98
99 # Handle custom Mint Ending.
100 if ap.custom_mint_ending != "":
101 var panel_prefab = preload("res://objects/nodes/panel.tscn")
102 var tpl_prefab = preload("res://objects/nodes/listeners/teleportListener.tscn")
103
104 var mint_ending = root.get_node("/root/scene/Components/Endings/mint_ending")
105
106 var mint_panel = panel_prefab.instantiate()
107 mint_panel.name = "mint_panel"
108 mint_panel.clue = ap.custom_mint_ending
109 mint_panel.symbol = ""
110 mint_panel.answer = ap.custom_mint_ending
111 mint_panel.position = Vector3(-63, 3, -29)
112 mint_panel.rotation_degrees = Vector3(-45, 90, 0)
113 root.get_node("/root/scene").add_child.call_deferred(mint_panel)
114
115 var mint_tpl = tpl_prefab.instantiate()
116 mint_tpl.name = "mint_tpl"
117 mint_tpl.teleport_point = mint_ending.position
118 mint_tpl.teleport_rotate = mint_ending.rotation_degrees
119 mint_tpl.target_path = mint_ending
120 mint_tpl.senders.append(NodePath("/root/scene/mint_panel"))
121 root.get_node("/root/scene").add_child.call_deferred(mint_tpl)
122
123 var mint_tpl2 = tpl_prefab.instantiate()
124 mint_tpl2.name = "mint_tpl2"
125 mint_tpl2.teleport_point = Vector3(0, -1000, 0)
126 mint_tpl2.target_path = mint_panel
127 mint_tpl2.senders.append(NodePath("/root/scene/mint_panel"))
128 root.get_node("/root/scene").add_child.call_deferred(mint_tpl2)
129
130 mint_ending.position.y = -1000
131
77 132
78func _set_up_mastery_listener(root, name): 133func _set_up_mastery_listener(root, name):
79 var prefab = preload("res://objects/nodes/listeners/unlockReaderListener.tscn") 134 var prefab = preload("res://objects/nodes/listeners/unlockReaderListener.tscn")
diff --git a/apworld/client/player.gd b/apworld/client/player.gd index 5fac9fd..dabc15d 100644 --- a/apworld/client/player.gd +++ b/apworld/client/player.gd
@@ -13,6 +13,8 @@ func _ready():
13 13
14 var ap = global.get_node("Archipelago") 14 var ap = global.get_node("Archipelago")
15 var gamedata = global.get_node("Gamedata") 15 var gamedata = global.get_node("Gamedata")
16 var map_id = gamedata.map_id_by_name.get(global.map)
17 var map_data = gamedata.objects.get_maps()[map_id]
16 18
17 compass = global.get_node("Compass") 19 compass = global.get_node("Compass")
18 compass.visible = ap.show_compass 20 compass.visible = ap.show_compass
@@ -26,8 +28,33 @@ func _ready():
26 28
27 ap.update_job_well_done_sign() 29 ap.update_job_well_done_sign()
28 30
31 # Set up the RTE trigger, if there is one.
32 if map_data.has_rte_trigger_pos():
33 var oneShotListener_prefab = preload("res://objects/nodes/listeners/oneShotListener.tscn")
34 var triggerArea_prefab = preload("res://objects/nodes/triggerArea.tscn")
35 var unlockSetterListener_prefab = preload(
36 "res://objects/nodes/listeners/unlockSetterListener.tscn"
37 )
38
39 var triggerArea = triggerArea_prefab.instantiate()
40 triggerArea.name = "rte_triggerArea"
41 triggerArea.position = gamedata.vec3d_to_vector3(map_data.get_rte_trigger_pos())
42 triggerArea.scale = gamedata.vec3d_to_vector3(map_data.get_rte_trigger_scale())
43 get_parent().add_child.call_deferred(triggerArea)
44
45 var osl = oneShotListener_prefab.instantiate()
46 osl.name = "rte_osl"
47 osl.senders.append(NodePath("/root/scene/rte_triggerArea"))
48 get_parent().add_child.call_deferred(osl)
49
50 var usl = unlockSetterListener_prefab.instantiate()
51 usl.name = "rte_usl"
52 usl.key = "rte_%s" % global.map
53 usl.value = "unlocked"
54 usl.senders.append(NodePath("/root/scene/rte_osl"))
55 get_parent().add_child.call_deferred(usl)
56
29 # Set up door locations. 57 # Set up door locations.
30 var map_id = gamedata.map_id_by_name.get(global.map)
31 for door in gamedata.objects.get_doors(): 58 for door in gamedata.objects.get_doors():
32 if door.get_map_id() != map_id: 59 if door.get_map_id() != map_id:
33 continue 60 continue
@@ -169,6 +196,17 @@ func _ready():
169 minimap.visible = ap.show_minimap 196 minimap.visible = ap.show_minimap
170 get_parent().add_child.call_deferred(minimap) 197 get_parent().add_child.call_deferred(minimap)
171 198
199 if ap.music_mapping.has(global.map):
200 var song_setter = get_node_or_null("/root/scene/songSetter")
201 if song_setter:
202 song_setter.song_name = ap.music_mapping[global.map]
203 else:
204 var song_setter_prefab = preload("res://objects/nodes/songSetter.tscn")
205 song_setter = song_setter_prefab.instantiate()
206 song_setter.name = "songSetter"
207 song_setter.song_name = ap.music_mapping[global.map]
208 get_parent().add_child.call_deferred(song_setter)
209
172 super._ready() 210 super._ready()
173 211
174 await get_tree().process_frame 212 await get_tree().process_frame
diff --git a/apworld/client/rteMenu.gd b/apworld/client/rteMenu.gd index 5882d77..519f09f 100644 --- a/apworld/client/rteMenu.gd +++ b/apworld/client/rteMenu.gd
@@ -1,5 +1,7 @@
1extends "res://scripts/ui/rteMenu.gd" 1extends "res://scripts/ui/rteMenu.gd"
2 2
3var buttons = []
4
3 5
4func _readier(): 6func _readier():
5 var ap = global.get_node("Archipelago") 7 var ap = global.get_node("Archipelago")
@@ -8,5 +10,58 @@ func _readier():
8 get_node("rte_daedalus").show() 10 get_node("rte_daedalus").show()
9 11
10 switcher.preload_map("res://objects/scenes/daedalus.tscn") 12 switcher.preload_map("res://objects/scenes/daedalus.tscn")
13 elif !ap.rte_mapping.is_empty():
14 buttons = [$rte_the_plaza, $rte_the_gallery, $rte_daedalus, $rte_control_center]
15 for i in range(4):
16 buttons[i].name = "button_%d" % i
17 for i in range(4):
18 _setupButton(buttons[i], ap.rte_mapping[i])
19
20 refreshButtons()
11 else: 21 else:
12 super()._readier() 22 super()._readier()
23
24
25func _setupButton(button, map_name):
26 switcher.preload_map("res://objects/scenes/%s.tscn" % map_name)
27
28 button.hide()
29 button.text = map_name.replace("_", " ")
30 button.name = "rte_%s" % map_name
31 button.autowrap_mode = TextServer.AUTOWRAP_WORD
32
33 var ap = global.get_node("Archipelago")
34 if (
35 ap.fast_travel_access == ap.kFAST_TRAVEL_ACCESS_VANILLA
36 and !unlocks.data.has("rte_%s" % map_name)
37 ):
38 unlocks.data["rte_%s" % map_name] = ""
39
40
41func refreshButtons():
42 var ap = global.get_node("Archipelago")
43 if ap.rte_mapping.is_empty():
44 return
45
46 for i in range(4):
47 if _shouldShowButton(ap.rte_mapping[i]):
48 buttons[i].show()
49 else:
50 buttons[i].hide()
51
52
53func _shouldShowButton(map_name):
54 var ap = global.get_node("Archipelago")
55
56 if ap.fast_travel_access == ap.kFAST_TRAVEL_ACCESS_VANILLA:
57 return unlocks.data["rte_%s" % map_name] == "unlocked"
58 elif ap.fast_travel_access == ap.kFAST_TRAVEL_ACCESS_UNLOCKED:
59 return true
60 elif ap.fast_travel_access == ap.kFAST_TRAVEL_ACCESS_ITEMS:
61 var gamedata = global.get_node("Gamedata")
62 var map_id = gamedata.map_id_by_name[map_name]
63 var rte_ap_id = gamedata.objects.get_maps()[map_id].get_rte_ap_id()
64
65 return ap.client.hasItem(rte_ap_id)
66
67 return false
diff --git a/apworld/items.py b/apworld/items.py index 28158c3..143ccb1 100644 --- a/apworld/items.py +++ b/apworld/items.py
@@ -5,6 +5,8 @@ from BaseClasses import Item
5class Lingo2Item(Item): 5class Lingo2Item(Item):
6 game: str = "Lingo 2" 6 game: str = "Lingo 2"
7 7
8 is_letter: bool
9
8 10
9SYMBOL_ITEMS: dict[data_pb2.PuzzleSymbol, str] = { 11SYMBOL_ITEMS: dict[data_pb2.PuzzleSymbol, str] = {
10 data_pb2.PuzzleSymbol.SUN: "Sun Symbol", 12 data_pb2.PuzzleSymbol.SUN: "Sun Symbol",
@@ -28,4 +30,5 @@ SYMBOL_ITEMS: dict[data_pb2.PuzzleSymbol, str] = {
28 data_pb2.PuzzleSymbol.QUESTION: "Question Symbol", 30 data_pb2.PuzzleSymbol.QUESTION: "Question Symbol",
29} 31}
30 32
31ANTI_COLLECTABLE_TRAPS: list[str] = [f"Anti {letter}" for letter in "ABCDEFGHIJKLMNOPQRSTUVWXYZ"] 33ALL_LETTERS_UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
34ANTI_COLLECTABLE_TRAPS: list[str] = [f"Anti {letter}" for letter in ALL_LETTERS_UPPER]
diff --git a/apworld/locations.py b/apworld/locations.py index 3d619dc..174a0dd 100644 --- a/apworld/locations.py +++ b/apworld/locations.py
@@ -1,4 +1,13 @@
1from BaseClasses import Location 1from enum import Enum
2
3from BaseClasses import Location, Item
4from .items import Lingo2Item
5
6
7class LetterPlacementType(Enum):
8 ANY = 0
9 DISALLOW = 1
10 FORCE = 2
2 11
3 12
4class Lingo2Location(Location): 13class Lingo2Location(Location):
@@ -6,3 +15,19 @@ class Lingo2Location(Location):
6 15
7 port_id: int 16 port_id: int
8 goal: bool 17 goal: bool
18 letter_placement_type: LetterPlacementType
19
20 def set_up_letter_rule(self, lpt: LetterPlacementType):
21 self.letter_placement_type = lpt
22 self.item_rule = self._l2_item_rule
23
24 def _l2_item_rule(self, item: Item) -> bool:
25 if not isinstance(item, Lingo2Item):
26 return True
27
28 if self.letter_placement_type == LetterPlacementType.FORCE:
29 return item.is_letter
30 elif self.letter_placement_type == LetterPlacementType.DISALLOW:
31 return not item.is_letter
32
33 return True
diff --git a/apworld/options.py b/apworld/options.py index 063af21..c1eab33 100644 --- a/apworld/options.py +++ b/apworld/options.py
@@ -1,6 +1,6 @@
1from dataclasses import dataclass 1from dataclasses import dataclass
2 2
3from Options import PerGameCommonOptions, Toggle, Choice, DefaultOnToggle, Range, OptionSet 3from Options import PerGameCommonOptions, Toggle, Choice, DefaultOnToggle, Range, OptionSet, FreeText
4 4
5 5
6class ShuffleDoors(DefaultOnToggle): 6class ShuffleDoors(DefaultOnToggle):
@@ -44,6 +44,17 @@ class ShuffleLetters(Choice):
44 option_item_cyan = 4 44 option_item_cyan = 4
45 45
46 46
47class RestrictLetterPlacements(Toggle):
48 """
49 If enabled, letter items will be shuffled among letter locations in your local world. Shuffle Letters must be set to
50 Progressive or Item Cyan for this to be useful.
51
52 WARNING: This option may slow down generation. Additionally, it is only reliable with Shuffle Letters set to Item
53 Cyan. When set to Progressive, Shuffle Doors and Shuffle Symbols must be turned off.
54 """
55 display_name = "Restrict Letter Placements"
56
57
47class ShuffleSymbols(Toggle): 58class ShuffleSymbols(Toggle):
48 """ 59 """
49 If enabled, 19 items will be added to the pool, representing the different symbols that can appear on a panel. 60 If enabled, 19 items will be added to the pool, representing the different symbols that can appear on a panel.
@@ -167,6 +178,15 @@ class DaedalusRoofAccess(Toggle):
167 display_name = "Allow Daedalus Roof Access" 178 display_name = "Allow Daedalus Roof Access"
168 179
169 180
181class CustomMintEnding(FreeText):
182 """
183 If not blank, this will add a new panel that must be solved before collecting Mint Ending (EXIT in the Control
184 Center). The panel will only require typing the text provided for this option, which means the choice of letters
185 here has an impact on logic.
186 """
187 display_name = "Custom Mint Ending"
188
189
170class StrictPurpleEnding(DefaultOnToggle): 190class StrictPurpleEnding(DefaultOnToggle):
171 """ 191 """
172 If enabled, the player will be required to have all purple (level 1) letters in order to get Purple Ending. 192 If enabled, the player will be required to have all purple (level 1) letters in order to get Purple Ending.
@@ -245,12 +265,20 @@ class TrapPercentage(Range):
245 default = 0 265 default = 0
246 266
247 267
268class ShuffleMusic(Toggle):
269 """
270 If enabled, every map will be assigned a random music track.
271 """
272 display_name = "Shuffle Music"
273
274
248@dataclass 275@dataclass
249class Lingo2Options(PerGameCommonOptions): 276class Lingo2Options(PerGameCommonOptions):
250 shuffle_doors: ShuffleDoors 277 shuffle_doors: ShuffleDoors
251 shuffle_control_center_colors: ShuffleControlCenterColors 278 shuffle_control_center_colors: ShuffleControlCenterColors
252 shuffle_gallery_paintings: ShuffleGalleryPaintings 279 shuffle_gallery_paintings: ShuffleGalleryPaintings
253 shuffle_letters: ShuffleLetters 280 shuffle_letters: ShuffleLetters
281 restrict_letter_placements: RestrictLetterPlacements
254 shuffle_symbols: ShuffleSymbols 282 shuffle_symbols: ShuffleSymbols
255 shuffle_worldports: ShuffleWorldports 283 shuffle_worldports: ShuffleWorldports
256 keyholder_sanity: KeyholderSanity 284 keyholder_sanity: KeyholderSanity
@@ -261,9 +289,11 @@ class Lingo2Options(PerGameCommonOptions):
261 enable_gift_maps: EnableGiftMaps 289 enable_gift_maps: EnableGiftMaps
262 daedalus_only: DaedalusOnly 290 daedalus_only: DaedalusOnly
263 daedalus_roof_access: DaedalusRoofAccess 291 daedalus_roof_access: DaedalusRoofAccess
292 custom_mint_ending: CustomMintEnding
264 strict_purple_ending: StrictPurpleEnding 293 strict_purple_ending: StrictPurpleEnding
265 strict_cyan_ending: StrictCyanEnding 294 strict_cyan_ending: StrictCyanEnding
266 victory_condition: VictoryCondition 295 victory_condition: VictoryCondition
267 endings_requirement: EndingsRequirement 296 endings_requirement: EndingsRequirement
268 masteries_requirement: MasteriesRequirement 297 masteries_requirement: MasteriesRequirement
269 trap_percentage: TrapPercentage 298 trap_percentage: TrapPercentage
299 shuffle_music: ShuffleMusic
diff --git a/apworld/player_logic.py b/apworld/player_logic.py index a02856e..ea74266 100644 --- a/apworld/player_logic.py +++ b/apworld/player_logic.py
@@ -192,6 +192,7 @@ class AccessRequirements:
192class PlayerLocation(NamedTuple): 192class PlayerLocation(NamedTuple):
193 code: int | None 193 code: int | None
194 reqs: AccessRequirements 194 reqs: AccessRequirements
195 is_letter: bool = False
195 196
196 197
197class LetterBehavior(IntEnum): 198class LetterBehavior(IntEnum):
@@ -222,6 +223,7 @@ class Lingo2PlayerLogic:
222 double_letter_amount: dict[str, int] 223 double_letter_amount: dict[str, int]
223 goal_room_id: int 224 goal_room_id: int
224 rte_mapping: list[int] 225 rte_mapping: list[int]
226 custom_mint_ending: str | None
225 227
226 def __init__(self, world: "Lingo2World"): 228 def __init__(self, world: "Lingo2World"):
227 self.world = world 229 self.world = world
@@ -236,6 +238,7 @@ class Lingo2PlayerLogic:
236 self.real_items = list() 238 self.real_items = list()
237 self.starting_items = list() 239 self.starting_items = list()
238 self.double_letter_amount = dict() 240 self.double_letter_amount = dict()
241 self.custom_mint_ending = None
239 242
240 def should_shuffle_map(game_map) -> bool | set[int]: 243 def should_shuffle_map(game_map) -> bool | set[int]:
241 if world.options.daedalus_only: 244 if world.options.daedalus_only:
@@ -295,6 +298,18 @@ class Lingo2PlayerLogic:
295 self.shuffled_doors.update(set(door.id for door in world.static_logic.objects.doors 298 self.shuffled_doors.update(set(door.id for door in world.static_logic.objects.doors
296 if door.map_id == game_map.id and door.daedalus_only_allow)) 299 if door.map_id == game_map.id and door.daedalus_only_allow))
297 300
301 if (world.options.restrict_letter_placements
302 and world.options.shuffle_letters == ShuffleLetters.option_progressive
303 and (world.options.shuffle_doors or world.options.shuffle_symbols)):
304 raise OptionError(f"When Restrict Letter Placements is enabled and Shuffle Letters is set to Progressive, "
305 f"both Shuffle Doors and Shuffle Symbols must be disabled (Player {world.player}).")
306
307 if world.options.custom_mint_ending.value != "":
308 self.custom_mint_ending = ''.join(filter(str.isalpha, world.options.custom_mint_ending.value)).lower()
309
310 if len(self.custom_mint_ending) > 52:
311 raise OptionError(f"Custom Mint Ending should not be greater than 52 letters (Player {world.player}).")
312
298 maximum_masteries = 13 + len(world.options.enable_gift_maps.value) 313 maximum_masteries = 13 + len(world.options.enable_gift_maps.value)
299 if world.options.enable_icarus: 314 if world.options.enable_icarus:
300 maximum_masteries += 1 315 maximum_masteries += 1
@@ -406,9 +421,11 @@ class Lingo2PlayerLogic:
406 if not self.should_shuffle_room(letter.room_id): 421 if not self.should_shuffle_room(letter.room_id):
407 continue 422 continue
408 423
409 self.locations_by_room.setdefault(letter.room_id, []).append(PlayerLocation(letter.ap_id,
410 AccessRequirements()))
411 behavior = self.get_letter_behavior(letter.key, letter.level2) 424 behavior = self.get_letter_behavior(letter.key, letter.level2)
425
426 self.locations_by_room.setdefault(letter.room_id, []).append(
427 PlayerLocation(letter.ap_id, AccessRequirements(), behavior == LetterBehavior.ITEM))
428
412 if behavior == LetterBehavior.VANILLA: 429 if behavior == LetterBehavior.VANILLA:
413 if not world.for_tracker: 430 if not world.for_tracker:
414 letter_name = f"{letter.key.upper()}{'2' if letter.level2 else '1'}" 431 letter_name = f"{letter.key.upper()}{'2' if letter.level2 else '1'}"
diff --git a/apworld/regions.py b/apworld/regions.py index 500139f..3996153 100644 --- a/apworld/regions.py +++ b/apworld/regions.py
@@ -4,7 +4,7 @@ import BaseClasses
4from BaseClasses import Region, ItemClassification, Entrance 4from BaseClasses import Region, ItemClassification, Entrance
5from entrance_rando import randomize_entrances 5from entrance_rando import randomize_entrances
6from .items import Lingo2Item 6from .items import Lingo2Item
7from .locations import Lingo2Location 7from .locations import Lingo2Location, LetterPlacementType
8from .options import FastTravelAccess 8from .options import FastTravelAccess
9from .player_logic import AccessRequirements 9from .player_logic import AccessRequirements
10from .rules import make_location_lambda 10from .rules import make_location_lambda
@@ -25,6 +25,11 @@ def create_locations(room, new_region: Region, world: "Lingo2World", regions: di
25 new_location = Lingo2Location(world.player, world.static_logic.location_id_to_name[location.code], 25 new_location = Lingo2Location(world.player, world.static_logic.location_id_to_name[location.code],
26 location.code, new_region) 26 location.code, new_region)
27 new_location.access_rule = make_location_lambda(reqs, world, regions) 27 new_location.access_rule = make_location_lambda(reqs, world, regions)
28 if world.options.restrict_letter_placements:
29 if location.is_letter:
30 new_location.set_up_letter_rule(LetterPlacementType.FORCE)
31 else:
32 new_location.set_up_letter_rule(LetterPlacementType.DISALLOW)
28 new_region.locations.append(new_location) 33 new_region.locations.append(new_location)
29 34
30 for event_name, item_name in world.player_logic.event_loc_item_by_room.get(room.id, {}).items(): 35 for event_name, item_name in world.player_logic.event_loc_item_by_room.get(room.id, {}).items():
@@ -136,6 +141,10 @@ def create_regions(world: "Lingo2World"):
136 if connection.HasField("cyan_ending") and connection.cyan_ending and world.options.strict_cyan_ending: 141 if connection.HasField("cyan_ending") and connection.cyan_ending and world.options.strict_cyan_ending:
137 world.player_logic.add_solution_reqs(reqs, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz") 142 world.player_logic.add_solution_reqs(reqs, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz")
138 143
144 if (connection.HasField("mint_ending") and connection.mint_ending
145 and world.player_logic.custom_mint_ending is not None):
146 world.player_logic.add_solution_reqs(reqs, world.player_logic.custom_mint_ending)
147
139 reqs.simplify() 148 reqs.simplify()
140 reqs.remove_room(from_region) 149 reqs.remove_room(from_region)
141 150
diff --git a/data/door_groups.txtpb b/data/door_groups.txtpb index 0f704da..128cbb8 100644 --- a/data/door_groups.txtpb +++ b/data/door_groups.txtpb
@@ -174,3 +174,17 @@ door_groups {
174 name: "Lavender Cubes" 174 name: "Lavender Cubes"
175 } 175 }
176} 176}
177door_groups {
178 name: "Control Center - Perceptive Entrance"
179 type: SHUFFLE_GROUP
180 # This is a weird situation where there's two different ways to open the door
181 # and we want both to work in vanilla.
182 doors {
183 map: "control_center"
184 name: "Perceptive From Outside"
185 }
186 doors {
187 map: "control_center"
188 name: "Perceptive From Inside"
189 }
190}
diff --git a/data/ids.yaml b/data/ids.yaml index f9c59aa..c55cfa6 100644 --- a/data/ids.yaml +++ b/data/ids.yaml
@@ -4785,6 +4785,7 @@ progressives:
4785 Icarus Quick Travel: 2933 4785 Icarus Quick Travel: 2933
4786 Progressive Gold Ending: 2753 4786 Progressive Gold Ending: 2753
4787door_groups: 4787door_groups:
4788 Control Center - Perceptive Entrance: 3424
4788 Control Center Blue Doors: 2788 4789 Control Center Blue Doors: 2788
4789 Control Center Brown Doors: 2787 4790 Control Center Brown Doors: 2787
4790 Control Center Orange Doors: 2786 4791 Control Center Orange Doors: 2786
diff --git a/data/maps/control_center/connections.txtpb b/data/maps/control_center/connections.txtpb index 432d39d..5dc2890 100644 --- a/data/maps/control_center/connections.txtpb +++ b/data/maps/control_center/connections.txtpb
@@ -17,6 +17,7 @@ connections {
17 from_room: "Main Area" 17 from_room: "Main Area"
18 to_room: "Mint Ending" 18 to_room: "Mint Ending"
19 door { name: "Mint Ending Door" } 19 door { name: "Mint Ending Door" }
20 mint_ending: true
20} 21}
21connections { 22connections {
22 from_room: "Main Area" 23 from_room: "Main Area"
diff --git a/data/maps/control_center/doors.txtpb b/data/maps/control_center/doors.txtpb index bec8714..c64274a 100644 --- a/data/maps/control_center/doors.txtpb +++ b/data/maps/control_center/doors.txtpb
@@ -114,7 +114,7 @@ doors {
114} 114}
115doors { 115doors {
116 name: "Perceptive From Inside" 116 name: "Perceptive From Inside"
117 type: LOCATION_ONLY 117 type: STANDARD
118 panels { room: "Perceptive Entrance" name: "PART" } 118 panels { room: "Perceptive Entrance" name: "PART" }
119 location_room: "Perceptive Entrance" 119 location_room: "Perceptive Entrance"
120} 120}
diff --git a/data/maps/four_rooms/metadata.txtpb b/data/maps/four_rooms/metadata.txtpb index ba66847..d0d7133 100644 --- a/data/maps/four_rooms/metadata.txtpb +++ b/data/maps/four_rooms/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "Four Rooms" 1display_name: "Four Rooms"
2rte_room: "Synonyms Room" 2rte_room: "Synonyms Room"
3rte_trigger_pos { x: 20 y: 0 z: -2.5 }
4rte_trigger_scale { x: 6 y: 1 z: 8 }
diff --git a/data/maps/icarus/metadata.txtpb b/data/maps/icarus/metadata.txtpb index c2a3656..3a45887 100644 --- a/data/maps/icarus/metadata.txtpb +++ b/data/maps/icarus/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "Icarus" 1display_name: "Icarus"
2type: ICARUS 2type: ICARUS
3rte_room: "Welcome Spine (Obverse)" 3rte_room: "Welcome Spine (Obverse)"
4rte_trigger_pos { x: 60 y: -3 z: 1 }
5rte_trigger_scale { x: 6 y: 1 z: 7 }
4# The map's mastery is created at runtime. 6# The map's mastery is created at runtime.
5custom_nodes: "Components/Collectables/collectable" 7custom_nodes: "Components/Collectables/collectable"
diff --git a/data/maps/the_advanced/metadata.txtpb b/data/maps/the_advanced/metadata.txtpb index 71d3925..db1cf5f 100644 --- a/data/maps/the_advanced/metadata.txtpb +++ b/data/maps/the_advanced/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Advanced" 1display_name: "The Advanced"
2type: GIFT_MAP 2type: GIFT_MAP
3rte_room: "Main Area" 3rte_room: "Main Area"
4rte_trigger_pos { x: 0 y: 0 z: 4 }
5rte_trigger_scale { x: 6 y: 1 z: 6 }
4# The map's mastery is created at runtime. 6# The map's mastery is created at runtime.
5custom_nodes: "Components/Collectables/collectable" 7custom_nodes: "Components/Collectables/collectable"
diff --git a/data/maps/the_ancient/metadata.txtpb b/data/maps/the_ancient/metadata.txtpb index 0f321dd..c44473b 100644 --- a/data/maps/the_ancient/metadata.txtpb +++ b/data/maps/the_ancient/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Ancient" 1display_name: "The Ancient"
2rte_room: "Outside" 2rte_room: "Outside"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 6 y: 1 z: 6 }
diff --git a/data/maps/the_bearer/metadata.txtpb b/data/maps/the_bearer/metadata.txtpb index 003473a..4dc0ac5 100644 --- a/data/maps/the_bearer/metadata.txtpb +++ b/data/maps/the_bearer/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Bearer" 1display_name: "The Bearer"
2rte_room: "Entry" 2rte_room: "Entry"
3rte_trigger_pos { x: 0 y: 0 z: -4 }
4rte_trigger_scale { x: 6 y: 1 z: 6 }
diff --git a/data/maps/the_between/metadata.txtpb b/data/maps/the_between/metadata.txtpb index 6134447..00e5ce9 100644 --- a/data/maps/the_between/metadata.txtpb +++ b/data/maps/the_between/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Between" 1display_name: "The Between"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 13 y: 1 z: 13 }
diff --git a/data/maps/the_butterfly/metadata.txtpb b/data/maps/the_butterfly/metadata.txtpb index 5933359..d7a64ce 100644 --- a/data/maps/the_butterfly/metadata.txtpb +++ b/data/maps/the_butterfly/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Butterfly" 1display_name: "The Butterfly"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: -15.5 y: 0 z: 15.5 }
4rte_trigger_scale { x: 8 y: 1 z: 8 }
diff --git a/data/maps/the_charismatic/metadata.txtpb b/data/maps/the_charismatic/metadata.txtpb index 740c04a..1555cba 100644 --- a/data/maps/the_charismatic/metadata.txtpb +++ b/data/maps/the_charismatic/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Charismatic" 1display_name: "The Charismatic"
2type: GIFT_MAP 2type: GIFT_MAP
3rte_room: "Main Area" 3rte_room: "Main Area"
4rte_trigger_pos { x: 0 y: 0 z: 0 }
5rte_trigger_scale { x: 3 y: 1 z: 10 }
4# The map's mastery is created at runtime. 6# The map's mastery is created at runtime.
5custom_nodes: "Components/Collectables/collectable" 7custom_nodes: "Components/Collectables/collectable"
diff --git a/data/maps/the_colorful/metadata.txtpb b/data/maps/the_colorful/metadata.txtpb index 1300c79..0038cff 100644 --- a/data/maps/the_colorful/metadata.txtpb +++ b/data/maps/the_colorful/metadata.txtpb
@@ -1,4 +1,6 @@
1display_name: "The Colorful" 1display_name: "The Colorful"
2rte_room: "White Room" 2rte_room: "White Room"
3rte_trigger_pos { x: 0 y: 0 z: 10 }
4rte_trigger_scale { x: 4 y: 1 z: 4 }
3# This has something to do with the FISH/FISHES proxy. 5# This has something to do with the FISH/FISHES proxy.
4excluded_nodes: "Components/panel_fake" 6excluded_nodes: "Components/panel_fake"
diff --git a/data/maps/the_congruent/metadata.txtpb b/data/maps/the_congruent/metadata.txtpb index 038bbd6..da3919d 100644 --- a/data/maps/the_congruent/metadata.txtpb +++ b/data/maps/the_congruent/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Congruent" 1display_name: "The Congruent"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 6 y: 1 z: 6 }
3worldport_entrance { 5worldport_entrance {
4 room: "Main Area" 6 room: "Main Area"
5 name: "DARKROOM" 7 name: "DARKROOM"
diff --git a/data/maps/the_crystalline/metadata.txtpb b/data/maps/the_crystalline/metadata.txtpb index 2447af6..4863264 100644 --- a/data/maps/the_crystalline/metadata.txtpb +++ b/data/maps/the_crystalline/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Crystalline" 1display_name: "The Crystalline"
2type: GIFT_MAP 2type: GIFT_MAP
3rte_room: "Main Area" 3rte_room: "Main Area"
4rte_trigger_pos { x: 0 y: 0 z: 0 }
5rte_trigger_scale { x: 10 y: 1 z: 10 }
4# The map's mastery is created at runtime. 6# The map's mastery is created at runtime.
5custom_nodes: "Components/Collectables/collectable" 7custom_nodes: "Components/Collectables/collectable"
diff --git a/data/maps/the_darkroom/metadata.txtpb b/data/maps/the_darkroom/metadata.txtpb index 0b122e9..7b5d539 100644 --- a/data/maps/the_darkroom/metadata.txtpb +++ b/data/maps/the_darkroom/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Darkroom" 1display_name: "The Darkroom"
2rte_room: "First Room" 2rte_room: "First Room"
3rte_trigger_pos { x: 0 y: 0 z: 1 }
4rte_trigger_scale { x: 14 y: 1 z: 13 }
diff --git a/data/maps/the_digital/metadata.txtpb b/data/maps/the_digital/metadata.txtpb index ce2f2c5..001fe55 100644 --- a/data/maps/the_digital/metadata.txtpb +++ b/data/maps/the_digital/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Digital" 1display_name: "The Digital"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: -9 y: 0 z: -5 }
4rte_trigger_scale { x: 15 y: 1 z: 15 }
diff --git a/data/maps/the_double_sided/metadata.txtpb b/data/maps/the_double_sided/metadata.txtpb index 1bcf6ac..5d60122 100644 --- a/data/maps/the_double_sided/metadata.txtpb +++ b/data/maps/the_double_sided/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Double Sided" 1display_name: "The Double Sided"
2rte_room: "Start" 2rte_room: "Start"
3rte_trigger_pos { x: 0 y: 0 z: -4 }
4rte_trigger_scale { x: 4 y: 1 z: 4 }
3worldport_entrance { 5worldport_entrance {
4 room: "Start" 6 room: "Start"
5 name: "DARKROOM" 7 name: "DARKROOM"
diff --git a/data/maps/the_extravagant/metadata.txtpb b/data/maps/the_extravagant/metadata.txtpb index 77d3b4b..f4604ab 100644 --- a/data/maps/the_extravagant/metadata.txtpb +++ b/data/maps/the_extravagant/metadata.txtpb
@@ -1,4 +1,6 @@
1display_name: "The Extravagant" 1display_name: "The Extravagant"
2rte_room: "Y Minus First Floor" 2rte_room: "Y Minus First Floor"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 6 y: 1 z: 6 }
3# This appears to be completely inaccessible. 5# This appears to be completely inaccessible.
4excluded_nodes: "Components/Warps/worldport" 6excluded_nodes: "Components/Warps/worldport"
diff --git a/data/maps/the_fuzzy/metadata.txtpb b/data/maps/the_fuzzy/metadata.txtpb index ded955b..75d6ff6 100644 --- a/data/maps/the_fuzzy/metadata.txtpb +++ b/data/maps/the_fuzzy/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Fuzzy" 1display_name: "The Fuzzy"
2type: GIFT_MAP 2type: GIFT_MAP
3rte_room: "Main Area" 3rte_room: "Main Area"
4rte_trigger_pos { x: 0 y: 0 z: 4 }
5rte_trigger_scale { x: 6 y: 1 z: 6 }
4# The map's mastery is created at runtime. 6# The map's mastery is created at runtime.
5custom_nodes: "Components/Collectables/collectable" 7custom_nodes: "Components/Collectables/collectable"
diff --git a/data/maps/the_graveyard/metadata.txtpb b/data/maps/the_graveyard/metadata.txtpb index 47a48e0..d97eb88 100644 --- a/data/maps/the_graveyard/metadata.txtpb +++ b/data/maps/the_graveyard/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Graveyard" 1display_name: "The Graveyard"
2rte_room: "Outside" 2rte_room: "Outside"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 8 y: 1 z: 8 }
3# These really shouldn't be shuffled because it would make Black Ending trivial. 5# These really shouldn't be shuffled because it would make Black Ending trivial.
4excluded_nodes: "Components/Paintings/grave" 6excluded_nodes: "Components/Paintings/grave"
5excluded_nodes: "Components/Paintings/grave2" 7excluded_nodes: "Components/Paintings/grave2"
diff --git a/data/maps/the_great/metadata.txtpb b/data/maps/the_great/metadata.txtpb index 7bbecd4..bbea189 100644 --- a/data/maps/the_great/metadata.txtpb +++ b/data/maps/the_great/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Great" 1display_name: "The Great"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 24 y: 0 z: 1 }
4rte_trigger_scale { x: 35 y: 1 z: 14 }
3# This can't be shuffled because it is tilted. 5# This can't be shuffled because it is tilted.
4excluded_nodes: "Components/Paintings/u" 6excluded_nodes: "Components/Paintings/u"
5# This can't be shuffled because it is on the ground. 7# This can't be shuffled because it is on the ground.
diff --git a/data/maps/the_hive/metadata.txtpb b/data/maps/the_hive/metadata.txtpb index 7be7b9e..d89d2ff 100644 --- a/data/maps/the_hive/metadata.txtpb +++ b/data/maps/the_hive/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Hive" 1display_name: "The Hive"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: -26 y: 0 z: -19 }
4rte_trigger_scale { x: 60 y: 10 z: 60 }
diff --git a/data/maps/the_impressive/metadata.txtpb b/data/maps/the_impressive/metadata.txtpb index 7a0a052..d05595d 100644 --- a/data/maps/the_impressive/metadata.txtpb +++ b/data/maps/the_impressive/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Impressive" 1display_name: "The Impressive"
2rte_room: "Lobby" 2rte_room: "Lobby"
3rte_trigger_pos { x: 0 y: 0 z: 5 }
4rte_trigger_scale { x: 6 y: 1 z: 10 }
3# These are apparently little eyes on the Green Eye panel pedestals? I don't 5# These are apparently little eyes on the Green Eye panel pedestals? I don't
4# think they're ever visible in gameplay. 6# think they're ever visible in gameplay.
5excluded_nodes: "Meshes/eye" 7excluded_nodes: "Meshes/eye"
diff --git a/data/maps/the_invisible/metadata.txtpb b/data/maps/the_invisible/metadata.txtpb index e980466..e995085 100644 --- a/data/maps/the_invisible/metadata.txtpb +++ b/data/maps/the_invisible/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Invisible" 1display_name: "The Invisible"
2rte_room: "Entrance" 2rte_room: "Entrance"
3rte_trigger_pos { x: 0 y: 0 z: -57 }
4rte_trigger_scale { x: 12 y: 1 z: 12 }
diff --git a/data/maps/the_jubilant/metadata.txtpb b/data/maps/the_jubilant/metadata.txtpb index 019b0b2..66fb7d2 100644 --- a/data/maps/the_jubilant/metadata.txtpb +++ b/data/maps/the_jubilant/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Jubilant" 1display_name: "The Jubilant"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 0 y: 0 z: 2 }
4rte_trigger_scale { x: 8 y: 1 z: 8 }
3worldport_entrance { 5worldport_entrance {
4 room: "Main Area" 6 room: "Main Area"
5 name: "GREAT" 7 name: "GREAT"
diff --git a/data/maps/the_keen/metadata.txtpb b/data/maps/the_keen/metadata.txtpb index 8417c2e..93a9eef 100644 --- a/data/maps/the_keen/metadata.txtpb +++ b/data/maps/the_keen/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Keen" 1display_name: "The Keen"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 6 y: 1 z: 6 }
3worldport_entrance { 5worldport_entrance {
4 room: "Main Area" 6 room: "Main Area"
5 name: "GREAT" 7 name: "GREAT"
diff --git a/data/maps/the_liberated/metadata.txtpb b/data/maps/the_liberated/metadata.txtpb index ebedbec..bdff786 100644 --- a/data/maps/the_liberated/metadata.txtpb +++ b/data/maps/the_liberated/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Liberated" 1display_name: "The Liberated"
2rte_room: "Puzzle Room" 2rte_room: "Puzzle Room"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 6 y: 1 z: 6 }
3worldport_entrance { 5worldport_entrance {
4 room: "Puzzle Room" 6 room: "Puzzle Room"
5 name: "ENTRY" 7 name: "ENTRY"
diff --git a/data/maps/the_linear/metadata.txtpb b/data/maps/the_linear/metadata.txtpb index cc9b4ce..03930f8 100644 --- a/data/maps/the_linear/metadata.txtpb +++ b/data/maps/the_linear/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Linear" 1display_name: "The Linear"
2rte_room: "Room" 2rte_room: "Room"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 6 y: 1 z: 6 }
3worldport_entrance { 5worldport_entrance {
4 room: "Room" 6 room: "Room"
5 name: "GREAT" 7 name: "GREAT"
diff --git a/data/maps/the_lionized/metadata.txtpb b/data/maps/the_lionized/metadata.txtpb index 587143d..0beb352 100644 --- a/data/maps/the_lionized/metadata.txtpb +++ b/data/maps/the_lionized/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Lionized" 1display_name: "The Lionized"
2rte_room: "Puzzle Room" 2rte_room: "Puzzle Room"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 6 y: 1 z: 6 }
3worldport_entrance { 5worldport_entrance {
4 room: "Puzzle Room" 6 room: "Puzzle Room"
5 name: "ENTRY" 7 name: "ENTRY"
diff --git a/data/maps/the_literate/metadata.txtpb b/data/maps/the_literate/metadata.txtpb index 28f5ccd..ce4db7a 100644 --- a/data/maps/the_literate/metadata.txtpb +++ b/data/maps/the_literate/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Literate" 1display_name: "The Literate"
2rte_room: "Puzzle Room" 2rte_room: "Puzzle Room"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 6 y: 1 z: 6 }
3worldport_entrance { 5worldport_entrance {
4 room: "Puzzle Room" 6 room: "Puzzle Room"
5 name: "ENTRY" 7 name: "ENTRY"
diff --git a/data/maps/the_lively/metadata.txtpb b/data/maps/the_lively/metadata.txtpb index c088afe..101a265 100644 --- a/data/maps/the_lively/metadata.txtpb +++ b/data/maps/the_lively/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Lively" 1display_name: "The Lively"
2rte_room: "Puzzle Room" 2rte_room: "Puzzle Room"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 6 y: 1 z: 6 }
3worldport_entrance { 5worldport_entrance {
4 room: "Puzzle Room" 6 room: "Puzzle Room"
5 name: "BETWEEN" 7 name: "BETWEEN"
diff --git a/data/maps/the_nuanced/metadata.txtpb b/data/maps/the_nuanced/metadata.txtpb index a3405ff..9d2e044 100644 --- a/data/maps/the_nuanced/metadata.txtpb +++ b/data/maps/the_nuanced/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Nuanced" 1display_name: "The Nuanced"
2rte_room: "Main Room" 2rte_room: "Main Room"
3rte_trigger_pos { x: 0 y: 0 z: 9 }
4rte_trigger_scale { x: 6 y: 1 z: 15 }
3worldport_entrance { 5worldport_entrance {
4 room: "Main Room" 6 room: "Main Room"
5 name: "UNYIELDING" 7 name: "UNYIELDING"
diff --git a/data/maps/the_orb/metadata.txtpb b/data/maps/the_orb/metadata.txtpb index a33dbf6..2b5c43f 100644 --- a/data/maps/the_orb/metadata.txtpb +++ b/data/maps/the_orb/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Orb" 1display_name: "The Orb"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 34 y: 0 z: 39 }
4rte_trigger_scale { x: 4 y: 1 z: 8 }
3# These are inaccessible, and were probably just copy pasted from the other 5# These are inaccessible, and were probably just copy pasted from the other
4# rooms. 6# rooms.
5excluded_nodes: "Components/Warps/worldport2" 7excluded_nodes: "Components/Warps/worldport2"
diff --git a/data/maps/the_owl/metadata.txtpb b/data/maps/the_owl/metadata.txtpb index 11d79b0..a9c4a6c 100644 --- a/data/maps/the_owl/metadata.txtpb +++ b/data/maps/the_owl/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Owl" 1display_name: "The Owl"
2rte_room: "R2C2 Bottom" 2rte_room: "R2C2 Bottom"
3rte_trigger_pos { x: 0 y: 0 z: 8 }
4rte_trigger_scale { x: 4 y: 1 z: 3 }
diff --git a/data/maps/the_parthenon/metadata.txtpb b/data/maps/the_parthenon/metadata.txtpb index 203d712..f3559ea 100644 --- a/data/maps/the_parthenon/metadata.txtpb +++ b/data/maps/the_parthenon/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Parthenon" 1display_name: "The Parthenon"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 0 y: 0 z: -15 }
4rte_trigger_scale { x: 18 y: 1 z: 30 }
diff --git a/data/maps/the_partial/metadata.txtpb b/data/maps/the_partial/metadata.txtpb index 9d5ad4a..dd090f5 100644 --- a/data/maps/the_partial/metadata.txtpb +++ b/data/maps/the_partial/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Partial" 1display_name: "The Partial"
2rte_room: "Obverse Side" 2rte_room: "Obverse Side"
3rte_trigger_pos { x: 0 y: 0 z: 5 }
4rte_trigger_scale { x: 13 y: 1 z: 16 }
diff --git a/data/maps/the_perceptive/metadata.txtpb b/data/maps/the_perceptive/metadata.txtpb index 22eb1d5..e67b84a 100644 --- a/data/maps/the_perceptive/metadata.txtpb +++ b/data/maps/the_perceptive/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Perceptive" 1display_name: "The Perceptive"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 30 y: 1 z: 20 }
3worldport_entrance { 5worldport_entrance {
4 room: "Main Area" 6 room: "Main Area"
5 name: "CC" 7 name: "CC"
diff --git a/data/maps/the_quiet/metadata.txtpb b/data/maps/the_quiet/metadata.txtpb index 9056fac..5cd177f 100644 --- a/data/maps/the_quiet/metadata.txtpb +++ b/data/maps/the_quiet/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Quiet" 1display_name: "The Quiet"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 0 y: 0 z: 2 }
4rte_trigger_scale { x: 8 y: 1 z: 8 }
3worldport_entrance { 5worldport_entrance {
4 room: "Main Area" 6 room: "Main Area"
5 name: "DAEDALUS" 7 name: "DAEDALUS"
diff --git a/data/maps/the_repetitive/metadata.txtpb b/data/maps/the_repetitive/metadata.txtpb index 4924048..a54d8b0 100644 --- a/data/maps/the_repetitive/metadata.txtpb +++ b/data/maps/the_repetitive/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Repetitive" 1display_name: "The Repetitive"
2rte_room: "Main Room" 2rte_room: "Main Room"
3rte_trigger_pos { x: 0 y: 0 z: 35.5 }
4rte_trigger_scale { x: 13 y: 1 z: 14 }
3# These paintings are directly above/behind panels and thus can't be entered. 5# These paintings are directly above/behind panels and thus can't be entered.
4excluded_nodes: "Meshes/eyeRed3" 6excluded_nodes: "Meshes/eyeRed3"
5excluded_nodes: "Meshes/eyeRed4" 7excluded_nodes: "Meshes/eyeRed4"
diff --git a/data/maps/the_revitalized/metadata.txtpb b/data/maps/the_revitalized/metadata.txtpb index ab64625..7046a17 100644 --- a/data/maps/the_revitalized/metadata.txtpb +++ b/data/maps/the_revitalized/metadata.txtpb
@@ -1,4 +1,6 @@
1display_name: "The Revitalized" 1display_name: "The Revitalized"
2rte_room: "Bye Room" 2rte_room: "Bye Room"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 14 y: 1 z: 14 }
3# Let's not include the demo (for now). 5# Let's not include the demo (for now).
4excluded_nodes: "Components/panel_demo" 6excluded_nodes: "Components/panel_demo"
diff --git a/data/maps/the_shop/metadata.txtpb b/data/maps/the_shop/metadata.txtpb index 4a17985..2777760 100644 --- a/data/maps/the_shop/metadata.txtpb +++ b/data/maps/the_shop/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Shop" 1display_name: "The Shop"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 0.5 y: 0 z: -12 }
4rte_trigger_scale { x: 15 y: 1 z: 19 }
diff --git a/data/maps/the_sirenic/metadata.txtpb b/data/maps/the_sirenic/metadata.txtpb index 9e1e5e7..7f30968 100644 --- a/data/maps/the_sirenic/metadata.txtpb +++ b/data/maps/the_sirenic/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Sirenic" 1display_name: "The Sirenic"
2rte_room: "Start" 2rte_room: "Start"
3rte_trigger_pos { x: 0 y: 0 z: 23 }
4rte_trigger_scale { x: 6 y: 1 z: 4 }
3worldport_entrance { 5worldport_entrance {
4 room: "Start" 6 room: "Start"
5 name: "PLAZA" 7 name: "PLAZA"
diff --git a/data/maps/the_stellar/metadata.txtpb b/data/maps/the_stellar/metadata.txtpb index 30b5ece..2aeb43c 100644 --- a/data/maps/the_stellar/metadata.txtpb +++ b/data/maps/the_stellar/metadata.txtpb
@@ -1,6 +1,8 @@
1display_name: "The Stellar" 1display_name: "The Stellar"
2type: GIFT_MAP 2type: GIFT_MAP
3rte_room: "Starting Room" 3rte_room: "Starting Room"
4rte_trigger_pos { x: 0 y: 0 z: -3 }
5rte_trigger_scale { x: 6 y: 1 z: 6 }
4# This panel does not appear to be accessible without sniping. 6# This panel does not appear to be accessible without sniping.
5excluded_nodes: "Panels/Room_1/panel_2" 7excluded_nodes: "Panels/Room_1/panel_2"
6# The map's mastery is created at runtime. 8# The map's mastery is created at runtime.
diff --git a/data/maps/the_stormy/metadata.txtpb b/data/maps/the_stormy/metadata.txtpb index 098218b..de85a3b 100644 --- a/data/maps/the_stormy/metadata.txtpb +++ b/data/maps/the_stormy/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Stormy" 1display_name: "The Stormy"
2rte_room: "Center" 2rte_room: "Center"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 8 y: 1 z: 8 }
diff --git a/data/maps/the_sturdy/metadata.txtpb b/data/maps/the_sturdy/metadata.txtpb index e6d997f..d99f18d 100644 --- a/data/maps/the_sturdy/metadata.txtpb +++ b/data/maps/the_sturdy/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Sturdy" 1display_name: "The Sturdy"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 0 y: 0 z: 2 }
4rte_trigger_scale { x: 40 y: 1 z: 40 }
3# Let's ignore the second half of the rainbows for now. 5# Let's ignore the second half of the rainbows for now.
4#excluded_nodes: "Components/Doors/Rainbow2/Hinge/rainbowMirrored" 6#excluded_nodes: "Components/Doors/Rainbow2/Hinge/rainbowMirrored"
5#excluded_nodes: "Components/Doors/Rainbow/Hinge/rainbowMirrored" 7#excluded_nodes: "Components/Doors/Rainbow/Hinge/rainbowMirrored"
diff --git a/data/maps/the_sun_temple/metadata.txtpb b/data/maps/the_sun_temple/metadata.txtpb index c64162e..6fa770b 100644 --- a/data/maps/the_sun_temple/metadata.txtpb +++ b/data/maps/the_sun_temple/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Sun Temple" 1display_name: "The Sun Temple"
2rte_room: "Entrance" 2rte_room: "Entrance"
3rte_trigger_pos { x: 0 y: 0 z: 2 }
4rte_trigger_scale { x: 10 y: 1 z: 10 }
3worldport_entrance { 5worldport_entrance {
4 room: "Entrance" 6 room: "Entrance"
5 name: "UNKEMPT" 7 name: "UNKEMPT"
diff --git a/data/maps/the_sweet/metadata.txtpb b/data/maps/the_sweet/metadata.txtpb index 9c3e7f5..e97f36f 100644 --- a/data/maps/the_sweet/metadata.txtpb +++ b/data/maps/the_sweet/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Sweet" 1display_name: "The Sweet"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 0 y: 0 z: -14.5 }
4rte_trigger_scale { x: 10 y: 1 z: 25 }
diff --git a/data/maps/the_symbolic/metadata.txtpb b/data/maps/the_symbolic/metadata.txtpb index d57fca2..41b9799 100644 --- a/data/maps/the_symbolic/metadata.txtpb +++ b/data/maps/the_symbolic/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Symbolic" 1display_name: "The Symbolic"
2rte_room: "White Room" 2rte_room: "White Room"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 6 y: 1 z: 6 }
3worldport_entrance { 5worldport_entrance {
4 room: "White Room" 6 room: "White Room"
5 name: "PLAZA" 7 name: "PLAZA"
diff --git a/data/maps/the_talented/metadata.txtpb b/data/maps/the_talented/metadata.txtpb index 0e68b9e..59e599c 100644 --- a/data/maps/the_talented/metadata.txtpb +++ b/data/maps/the_talented/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Talented" 1display_name: "The Talented"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 0 y: 0 z: 9 }
4rte_trigger_scale { x: 6 y: 1 z: 15 }
3worldport_entrance { 5worldport_entrance {
4 room: "Main Area" 6 room: "Main Area"
5 name: "GREAT" 7 name: "GREAT"
diff --git a/data/maps/the_tenacious/metadata.txtpb b/data/maps/the_tenacious/metadata.txtpb index 86ed1c5..55ea23d 100644 --- a/data/maps/the_tenacious/metadata.txtpb +++ b/data/maps/the_tenacious/metadata.txtpb
@@ -1,3 +1,5 @@
1display_name: "The Tenacious" 1display_name: "The Tenacious"
2rte_room: "Control Center Entrance" 2rte_room: "Control Center Entrance"
3rte_trigger_pos { x: 0 y: 0 z: 10 }
4rte_trigger_scale { x: 4 y: 1 z: 4 }
3daedalus_only_mode: DAED_ONLY_ALLOW 5daedalus_only_mode: DAED_ONLY_ALLOW
diff --git a/data/maps/the_three_doors/metadata.txtpb b/data/maps/the_three_doors/metadata.txtpb index bed023f..d2fa498 100644 --- a/data/maps/the_three_doors/metadata.txtpb +++ b/data/maps/the_three_doors/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Three Doors" 1display_name: "The Three Doors"
2rte_room: "First Second Room" 2rte_room: "First Second Room"
3rte_trigger_pos { x: -15 y: 0 z: 1 }
4rte_trigger_scale { x: 8 y: 1 z: 4 }
diff --git a/data/maps/the_tower/metadata.txtpb b/data/maps/the_tower/metadata.txtpb index 9d4fe0b..11ab3da 100644 --- a/data/maps/the_tower/metadata.txtpb +++ b/data/maps/the_tower/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Tower" 1display_name: "The Tower"
2rte_room: "First Floor" 2rte_room: "First Floor"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 8 y: 1 z: 8 }
3worldport_entrance { 5worldport_entrance {
4 room: "First Floor" 6 room: "First Floor"
5 name: "GREAT" 7 name: "GREAT"
diff --git a/data/maps/the_tree/metadata.txtpb b/data/maps/the_tree/metadata.txtpb index c52b946..dbe7a6e 100644 --- a/data/maps/the_tree/metadata.txtpb +++ b/data/maps/the_tree/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Tree" 1display_name: "The Tree"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 15 y: 1 z: 15 }
diff --git a/data/maps/the_unkempt/metadata.txtpb b/data/maps/the_unkempt/metadata.txtpb index eaa821f..c3fdb8c 100644 --- a/data/maps/the_unkempt/metadata.txtpb +++ b/data/maps/the_unkempt/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Unkempt" 1display_name: "The Unkempt"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: -12 y: 0 z: -2 }
4rte_trigger_scale { x: 20 y: 1 z: 5 }
diff --git a/data/maps/the_unyielding/metadata.txtpb b/data/maps/the_unyielding/metadata.txtpb index 311a966..2e67c0d 100644 --- a/data/maps/the_unyielding/metadata.txtpb +++ b/data/maps/the_unyielding/metadata.txtpb
@@ -1,2 +1,4 @@
1display_name: "The Unyielding" 1display_name: "The Unyielding"
2rte_room: "Digital Entrance" 2rte_room: "Digital Entrance"
3rte_trigger_pos { x: 0 y: 0 z: -6 }
4rte_trigger_scale { x: 6 y: 1 z: 6 }
diff --git a/data/maps/the_wise/metadata.txtpb b/data/maps/the_wise/metadata.txtpb index 282ebe9..e9b77ad 100644 --- a/data/maps/the_wise/metadata.txtpb +++ b/data/maps/the_wise/metadata.txtpb
@@ -1,4 +1,6 @@
1display_name: "The Wise" 1display_name: "The Wise"
2rte_room: "Entry" 2rte_room: "Entry"
3rte_trigger_pos { x: 0 y: 0 z: 22.5 }
4rte_trigger_scale { x: 6 y: 1 z: 6 }
3# This port is out of bounds. 5# This port is out of bounds.
4excluded_nodes: "Components/Warps/worldport" 6excluded_nodes: "Components/Warps/worldport"
diff --git a/data/maps/the_wondrous/metadata.txtpb b/data/maps/the_wondrous/metadata.txtpb index 88ca318..ef453aa 100644 --- a/data/maps/the_wondrous/metadata.txtpb +++ b/data/maps/the_wondrous/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Wondrous" 1display_name: "The Wondrous"
2rte_room: "Entry" 2rte_room: "Entry"
3rte_trigger_pos { x: 8 y: 0 z: 40 }
4rte_trigger_scale { x: 6 y: 1 z: 6 }
3worldport_entrance { 5worldport_entrance {
4 room: "Entry" 6 room: "Entry"
5 name: "DAEDALUS" 7 name: "DAEDALUS"
diff --git a/data/maps/the_words/metadata.txtpb b/data/maps/the_words/metadata.txtpb index b016db0..0fdee3f 100644 --- a/data/maps/the_words/metadata.txtpb +++ b/data/maps/the_words/metadata.txtpb
@@ -1,5 +1,7 @@
1display_name: "The Words" 1display_name: "The Words"
2rte_room: "Main Area" 2rte_room: "Main Area"
3rte_trigger_pos { x: 0 y: 0 z: 0 }
4rte_trigger_scale { x: 8 y: 1 z: 8 }
3# These are old proxies of the main room's panels that are not linked up 5# These are old proxies of the main room's panels that are not linked up
4# anymore. 6# anymore.
5excluded_nodes: "Panels/Proxies/panel_3" 7excluded_nodes: "Panels/Proxies/panel_3"
diff --git a/data/metadata.txtpb b/data/metadata.txtpb index cff3f39..c362be0 100644 --- a/data/metadata.txtpb +++ b/data/metadata.txtpb
@@ -1,7 +1,7 @@
1version { 1version {
2 major: 8 2 major: 9
3 minor: 1 3 minor: 0
4 patch: 1 4 patch: 0
5} 5}
6# Filler item. 6# Filler item.
7special_names: "A Job Well Done" 7special_names: "A Job Well Done"
diff --git a/proto/data.proto b/proto/data.proto index 3330666..619b3d3 100644 --- a/proto/data.proto +++ b/proto/data.proto
@@ -136,6 +136,7 @@ message Connection {
136 optional bool roof_access = 7; 136 optional bool roof_access = 7;
137 optional bool purple_ending = 8; 137 optional bool purple_ending = 8;
138 optional bool cyan_ending = 9; 138 optional bool cyan_ending = 9;
139 optional bool mint_ending = 11;
139 optional bool vanilla_only = 10; 140 optional bool vanilla_only = 10;
140} 141}
141 142
@@ -291,6 +292,8 @@ message Map {
291 292
292 optional uint64 rte_room = 7; 293 optional uint64 rte_room = 7;
293 optional uint64 rte_ap_id = 8; 294 optional uint64 rte_ap_id = 8;
295 optional Vec3d rte_trigger_pos = 9;
296 optional Vec3d rte_trigger_scale = 10;
294} 297}
295 298
296message Progressive { 299message Progressive {
diff --git a/proto/human.proto b/proto/human.proto index 484369e..5cd8ce7 100644 --- a/proto/human.proto +++ b/proto/human.proto
@@ -79,6 +79,10 @@ message HumanConnection {
79 // when the Strict Cyan Ending option is on. 79 // when the Strict Cyan Ending option is on.
80 optional bool cyan_ending = 10; 80 optional bool cyan_ending = 10;
81 81
82 // This means that the connection should additionally require being able to
83 // type a specific text string when Custom Mint Ending is on.
84 optional bool mint_ending = 12;
85
82 // This means that the connection only exists when doors are not shuffled. 86 // This means that the connection only exists when doors are not shuffled.
83 optional bool vanilla_only = 11; 87 optional bool vanilla_only = 11;
84} 88}
@@ -239,6 +243,8 @@ message HumanMap {
239 243
240 optional PortIdentifier worldport_entrance = 3; 244 optional PortIdentifier worldport_entrance = 3;
241 optional string rte_room = 7; 245 optional string rte_room = 7;
246 optional Vec3d rte_trigger_pos = 8;
247 optional Vec3d rte_trigger_scale = 9;
242 248
243 // These two fields are used by the validator and nothing else. excluded_nodes 249 // These two fields are used by the validator and nothing else. excluded_nodes
244 // are objects in the tscn that are intentionally not mentioned in the txtpb. 250 // are objects in the tscn that are intentionally not mentioned in the txtpb.
diff --git a/tools/datapacker/main.cpp b/tools/datapacker/main.cpp index f1ef10e..4ecde74 100644 --- a/tools/datapacker/main.cpp +++ b/tools/datapacker/main.cpp
@@ -105,6 +105,11 @@ class DataPacker {
105 map.set_rte_room(container_.FindOrAddRoom(map_name, metadata.rte_room(), 105 map.set_rte_room(container_.FindOrAddRoom(map_name, metadata.rte_room(),
106 std::nullopt)); 106 std::nullopt));
107 } 107 }
108
109 if (metadata.has_rte_trigger_pos()) {
110 *map.mutable_rte_trigger_pos() = metadata.rte_trigger_pos();
111 *map.mutable_rte_trigger_scale() = metadata.rte_trigger_scale();
112 }
108 } 113 }
109 114
110 void ProcessRooms(std::filesystem::path path, 115 void ProcessRooms(std::filesystem::path path,
@@ -528,6 +533,11 @@ class DataPacker {
528 r_connection.set_cyan_ending(human_connection.cyan_ending()); 533 r_connection.set_cyan_ending(human_connection.cyan_ending());
529 } 534 }
530 535
536 if (human_connection.has_mint_ending()) {
537 f_connection.set_mint_ending(human_connection.mint_ending());
538 r_connection.set_mint_ending(human_connection.mint_ending());
539 }
540
531 if (human_connection.has_vanilla_only()) { 541 if (human_connection.has_vanilla_only()) {
532 f_connection.set_vanilla_only(human_connection.vanilla_only()); 542 f_connection.set_vanilla_only(human_connection.vanilla_only());
533 r_connection.set_vanilla_only(human_connection.vanilla_only()); 543 r_connection.set_vanilla_only(human_connection.vanilla_only());