diff options
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 | |||
| 27 | Compatibility 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 | |||
| 35 | Download: | ||
| 36 | [lingo2.apworld](https://files.fourisland.com/releases/lingo2-archipelago/apworld/v9.0.0/lingo2.apworld)<br/> | ||
| 37 | Template YAML: | ||
| 38 | [Lingo 2.yaml](https://files.fourisland.com/releases/lingo2-archipelago/apworld/v9.0.0/Lingo%202.yaml)<br/> | ||
| 39 | Source: [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 | |||
| 7 | from Options import OptionError | 7 | from Options import OptionError |
| 8 | from settings import Group, UserFilePath | 8 | from settings import Group, UserFilePath |
| 9 | from worlds.AutoWorld import WebWorld, World | 9 | from worlds.AutoWorld import WebWorld, World |
| 10 | from .items import Lingo2Item, ANTI_COLLECTABLE_TRAPS | 10 | from .items import Lingo2Item, ANTI_COLLECTABLE_TRAPS, ALL_LETTERS_UPPER |
| 11 | from .options import Lingo2Options | 11 | from .options import Lingo2Options |
| 12 | from .player_logic import Lingo2PlayerLogic | 12 | from .player_logic import Lingo2PlayerLogic |
| 13 | from .regions import create_regions, shuffle_entrances, connect_ports_from_ut | 13 | from .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 = {} | |||
| 16 | var location_name_by_id = {} | 16 | var location_name_by_id = {} |
| 17 | var ending_display_name_by_name = {} | 17 | var ending_display_name_by_name = {} |
| 18 | var port_id_by_ap_id = {} | 18 | var port_id_by_ap_id = {} |
| 19 | var map_id_by_rte_ap_id = {} | ||
| 19 | 20 | ||
| 20 | var kSYMBOL_ITEMS | 21 | var 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 | |||
| 309 | func 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 | |||
| 46 | const kCYAN_DOOR_BEHAVIOR_DOUBLE_LETTER = 1 | 46 | const kCYAN_DOOR_BEHAVIOR_DOUBLE_LETTER = 1 |
| 47 | const kCYAN_DOOR_BEHAVIOR_ITEM = 2 | 47 | const kCYAN_DOOR_BEHAVIOR_ITEM = 2 |
| 48 | 48 | ||
| 49 | const kFAST_TRAVEL_ACCESS_VANILLA = 0 | ||
| 50 | const kFAST_TRAVEL_ACCESS_UNLOCKED = 1 | ||
| 51 | const kFAST_TRAVEL_ACCESS_ITEMS = 2 | ||
| 52 | |||
| 49 | const kEndingNameByVictoryValue = { | 53 | const kEndingNameByVictoryValue = { |
| 50 | 0: "GRAY", | 54 | 0: "GRAY", |
| 51 | 1: "PURPLE", | 55 | 1: "PURPLE", |
| @@ -63,21 +67,26 @@ const kEndingNameByVictoryValue = { | |||
| 63 | } | 67 | } |
| 64 | 68 | ||
| 65 | var apworld_version = [0, 0, 0] | 69 | var apworld_version = [0, 0, 0] |
| 70 | var custom_mint_ending = "" | ||
| 66 | var cyan_door_behavior = kCYAN_DOOR_BEHAVIOR_H2 | 71 | var cyan_door_behavior = kCYAN_DOOR_BEHAVIOR_H2 |
| 67 | var daedalus_only = false | 72 | var daedalus_only = false |
| 68 | var daedalus_roof_access = false | 73 | var daedalus_roof_access = false |
| 69 | var enable_gift_maps = [] | 74 | var enable_gift_maps = [] |
| 70 | var enable_icarus = false | 75 | var enable_icarus = false |
| 71 | var endings_requirement = 0 | 76 | var endings_requirement = 0 |
| 77 | var fast_travel_access = 0 | ||
| 72 | var keyholder_sanity = false | 78 | var keyholder_sanity = false |
| 73 | var masteries_requirement = 0 | 79 | var masteries_requirement = 0 |
| 80 | var music_mapping = {} | ||
| 74 | var port_pairings = {} | 81 | var port_pairings = {} |
| 82 | var rte_mapping = [] | ||
| 75 | var shuffle_control_center_colors = false | 83 | var shuffle_control_center_colors = false |
| 76 | var shuffle_doors = false | 84 | var shuffle_doors = false |
| 77 | var shuffle_gallery_paintings = false | 85 | var shuffle_gallery_paintings = false |
| 78 | var shuffle_letters = kSHUFFLE_LETTERS_VANILLA | 86 | var shuffle_letters = kSHUFFLE_LETTERS_VANILLA |
| 79 | var shuffle_symbols = false | 87 | var shuffle_symbols = false |
| 80 | var shuffle_worldports = false | 88 | var shuffle_worldports = false |
| 89 | var slot_rng = null | ||
| 81 | var strict_cyan_ending = false | 90 | var strict_cyan_ending = false |
| 82 | var strict_purple_ending = false | 91 | var strict_purple_ending = false |
| 83 | var victory_condition = -1 | 92 | var 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 | ||
| 78 | func _set_up_mastery_listener(root, name): | 133 | func _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 @@ | |||
| 1 | extends "res://scripts/ui/rteMenu.gd" | 1 | extends "res://scripts/ui/rteMenu.gd" |
| 2 | 2 | ||
| 3 | var buttons = [] | ||
| 4 | |||
| 3 | 5 | ||
| 4 | func _readier(): | 6 | func _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 | |||
| 25 | func _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 | |||
| 41 | func 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 | |||
| 53 | func _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 | |||
| 5 | class Lingo2Item(Item): | 5 | class Lingo2Item(Item): |
| 6 | game: str = "Lingo 2" | 6 | game: str = "Lingo 2" |
| 7 | 7 | ||
| 8 | is_letter: bool | ||
| 9 | |||
| 8 | 10 | ||
| 9 | SYMBOL_ITEMS: dict[data_pb2.PuzzleSymbol, str] = { | 11 | SYMBOL_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 | ||
| 31 | ANTI_COLLECTABLE_TRAPS: list[str] = [f"Anti {letter}" for letter in "ABCDEFGHIJKLMNOPQRSTUVWXYZ"] | 33 | ALL_LETTERS_UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 34 | ANTI_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 @@ | |||
| 1 | from BaseClasses import Location | 1 | from enum import Enum |
| 2 | |||
| 3 | from BaseClasses import Location, Item | ||
| 4 | from .items import Lingo2Item | ||
| 5 | |||
| 6 | |||
| 7 | class LetterPlacementType(Enum): | ||
| 8 | ANY = 0 | ||
| 9 | DISALLOW = 1 | ||
| 10 | FORCE = 2 | ||
| 2 | 11 | ||
| 3 | 12 | ||
| 4 | class Lingo2Location(Location): | 13 | class 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 @@ | |||
| 1 | from dataclasses import dataclass | 1 | from dataclasses import dataclass |
| 2 | 2 | ||
| 3 | from Options import PerGameCommonOptions, Toggle, Choice, DefaultOnToggle, Range, OptionSet | 3 | from Options import PerGameCommonOptions, Toggle, Choice, DefaultOnToggle, Range, OptionSet, FreeText |
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | class ShuffleDoors(DefaultOnToggle): | 6 | class ShuffleDoors(DefaultOnToggle): |
| @@ -44,6 +44,17 @@ class ShuffleLetters(Choice): | |||
| 44 | option_item_cyan = 4 | 44 | option_item_cyan = 4 |
| 45 | 45 | ||
| 46 | 46 | ||
| 47 | class 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 | |||
| 47 | class ShuffleSymbols(Toggle): | 58 | class 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 | ||
| 181 | class 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 | |||
| 170 | class StrictPurpleEnding(DefaultOnToggle): | 190 | class 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 | ||
| 268 | class 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 |
| 249 | class Lingo2Options(PerGameCommonOptions): | 276 | class 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: | |||
| 192 | class PlayerLocation(NamedTuple): | 192 | class 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 | ||
| 197 | class LetterBehavior(IntEnum): | 198 | class 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 | |||
| 4 | from BaseClasses import Region, ItemClassification, Entrance | 4 | from BaseClasses import Region, ItemClassification, Entrance |
| 5 | from entrance_rando import randomize_entrances | 5 | from entrance_rando import randomize_entrances |
| 6 | from .items import Lingo2Item | 6 | from .items import Lingo2Item |
| 7 | from .locations import Lingo2Location | 7 | from .locations import Lingo2Location, LetterPlacementType |
| 8 | from .options import FastTravelAccess | 8 | from .options import FastTravelAccess |
| 9 | from .player_logic import AccessRequirements | 9 | from .player_logic import AccessRequirements |
| 10 | from .rules import make_location_lambda | 10 | from .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 | } |
| 177 | door_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 |
| 4787 | door_groups: | 4787 | door_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 | } |
| 21 | connections { | 22 | connections { |
| 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 | } |
| 115 | doors { | 115 | doors { |
| 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 @@ | |||
| 1 | display_name: "Four Rooms" | 1 | display_name: "Four Rooms" |
| 2 | rte_room: "Synonyms Room" | 2 | rte_room: "Synonyms Room" |
| 3 | rte_trigger_pos { x: 20 y: 0 z: -2.5 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "Icarus" | 1 | display_name: "Icarus" |
| 2 | type: ICARUS | 2 | type: ICARUS |
| 3 | rte_room: "Welcome Spine (Obverse)" | 3 | rte_room: "Welcome Spine (Obverse)" |
| 4 | rte_trigger_pos { x: 60 y: -3 z: 1 } | ||
| 5 | rte_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. |
| 5 | custom_nodes: "Components/Collectables/collectable" | 7 | custom_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 @@ | |||
| 1 | display_name: "The Advanced" | 1 | display_name: "The Advanced" |
| 2 | type: GIFT_MAP | 2 | type: GIFT_MAP |
| 3 | rte_room: "Main Area" | 3 | rte_room: "Main Area" |
| 4 | rte_trigger_pos { x: 0 y: 0 z: 4 } | ||
| 5 | rte_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. |
| 5 | custom_nodes: "Components/Collectables/collectable" | 7 | custom_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 @@ | |||
| 1 | display_name: "The Ancient" | 1 | display_name: "The Ancient" |
| 2 | rte_room: "Outside" | 2 | rte_room: "Outside" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Bearer" | 1 | display_name: "The Bearer" |
| 2 | rte_room: "Entry" | 2 | rte_room: "Entry" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: -4 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Between" | 1 | display_name: "The Between" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Butterfly" | 1 | display_name: "The Butterfly" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: -15.5 y: 0 z: 15.5 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Charismatic" | 1 | display_name: "The Charismatic" |
| 2 | type: GIFT_MAP | 2 | type: GIFT_MAP |
| 3 | rte_room: "Main Area" | 3 | rte_room: "Main Area" |
| 4 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 5 | rte_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. |
| 5 | custom_nodes: "Components/Collectables/collectable" | 7 | custom_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 @@ | |||
| 1 | display_name: "The Colorful" | 1 | display_name: "The Colorful" |
| 2 | rte_room: "White Room" | 2 | rte_room: "White Room" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 10 } | ||
| 4 | rte_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. |
| 4 | excluded_nodes: "Components/panel_fake" | 6 | excluded_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 @@ | |||
| 1 | display_name: "The Congruent" | 1 | display_name: "The Congruent" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_trigger_scale { x: 6 y: 1 z: 6 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Crystalline" | 1 | display_name: "The Crystalline" |
| 2 | type: GIFT_MAP | 2 | type: GIFT_MAP |
| 3 | rte_room: "Main Area" | 3 | rte_room: "Main Area" |
| 4 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 5 | rte_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. |
| 5 | custom_nodes: "Components/Collectables/collectable" | 7 | custom_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 @@ | |||
| 1 | display_name: "The Darkroom" | 1 | display_name: "The Darkroom" |
| 2 | rte_room: "First Room" | 2 | rte_room: "First Room" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 1 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Digital" | 1 | display_name: "The Digital" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: -9 y: 0 z: -5 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Double Sided" | 1 | display_name: "The Double Sided" |
| 2 | rte_room: "Start" | 2 | rte_room: "Start" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: -4 } | ||
| 4 | rte_trigger_scale { x: 4 y: 1 z: 4 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Extravagant" | 1 | display_name: "The Extravagant" |
| 2 | rte_room: "Y Minus First Floor" | 2 | rte_room: "Y Minus First Floor" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_trigger_scale { x: 6 y: 1 z: 6 } | ||
| 3 | # This appears to be completely inaccessible. | 5 | # This appears to be completely inaccessible. |
| 4 | excluded_nodes: "Components/Warps/worldport" | 6 | excluded_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 @@ | |||
| 1 | display_name: "The Fuzzy" | 1 | display_name: "The Fuzzy" |
| 2 | type: GIFT_MAP | 2 | type: GIFT_MAP |
| 3 | rte_room: "Main Area" | 3 | rte_room: "Main Area" |
| 4 | rte_trigger_pos { x: 0 y: 0 z: 4 } | ||
| 5 | rte_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. |
| 5 | custom_nodes: "Components/Collectables/collectable" | 7 | custom_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 @@ | |||
| 1 | display_name: "The Graveyard" | 1 | display_name: "The Graveyard" |
| 2 | rte_room: "Outside" | 2 | rte_room: "Outside" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_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. |
| 4 | excluded_nodes: "Components/Paintings/grave" | 6 | excluded_nodes: "Components/Paintings/grave" |
| 5 | excluded_nodes: "Components/Paintings/grave2" | 7 | excluded_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 @@ | |||
| 1 | display_name: "The Great" | 1 | display_name: "The Great" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 24 y: 0 z: 1 } | ||
| 4 | rte_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. |
| 4 | excluded_nodes: "Components/Paintings/u" | 6 | excluded_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 @@ | |||
| 1 | display_name: "The Hive" | 1 | display_name: "The Hive" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: -26 y: 0 z: -19 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Impressive" | 1 | display_name: "The Impressive" |
| 2 | rte_room: "Lobby" | 2 | rte_room: "Lobby" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 5 } | ||
| 4 | rte_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. |
| 5 | excluded_nodes: "Meshes/eye" | 7 | excluded_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 @@ | |||
| 1 | display_name: "The Invisible" | 1 | display_name: "The Invisible" |
| 2 | rte_room: "Entrance" | 2 | rte_room: "Entrance" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: -57 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Jubilant" | 1 | display_name: "The Jubilant" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 2 } | ||
| 4 | rte_trigger_scale { x: 8 y: 1 z: 8 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Keen" | 1 | display_name: "The Keen" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_trigger_scale { x: 6 y: 1 z: 6 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Liberated" | 1 | display_name: "The Liberated" |
| 2 | rte_room: "Puzzle Room" | 2 | rte_room: "Puzzle Room" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_trigger_scale { x: 6 y: 1 z: 6 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Linear" | 1 | display_name: "The Linear" |
| 2 | rte_room: "Room" | 2 | rte_room: "Room" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_trigger_scale { x: 6 y: 1 z: 6 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Lionized" | 1 | display_name: "The Lionized" |
| 2 | rte_room: "Puzzle Room" | 2 | rte_room: "Puzzle Room" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_trigger_scale { x: 6 y: 1 z: 6 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Literate" | 1 | display_name: "The Literate" |
| 2 | rte_room: "Puzzle Room" | 2 | rte_room: "Puzzle Room" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_trigger_scale { x: 6 y: 1 z: 6 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Lively" | 1 | display_name: "The Lively" |
| 2 | rte_room: "Puzzle Room" | 2 | rte_room: "Puzzle Room" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_trigger_scale { x: 6 y: 1 z: 6 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Nuanced" | 1 | display_name: "The Nuanced" |
| 2 | rte_room: "Main Room" | 2 | rte_room: "Main Room" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 9 } | ||
| 4 | rte_trigger_scale { x: 6 y: 1 z: 15 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Orb" | 1 | display_name: "The Orb" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 34 y: 0 z: 39 } | ||
| 4 | rte_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. |
| 5 | excluded_nodes: "Components/Warps/worldport2" | 7 | excluded_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 @@ | |||
| 1 | display_name: "The Owl" | 1 | display_name: "The Owl" |
| 2 | rte_room: "R2C2 Bottom" | 2 | rte_room: "R2C2 Bottom" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 8 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Parthenon" | 1 | display_name: "The Parthenon" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: -15 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Partial" | 1 | display_name: "The Partial" |
| 2 | rte_room: "Obverse Side" | 2 | rte_room: "Obverse Side" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 5 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Perceptive" | 1 | display_name: "The Perceptive" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_trigger_scale { x: 30 y: 1 z: 20 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Quiet" | 1 | display_name: "The Quiet" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 2 } | ||
| 4 | rte_trigger_scale { x: 8 y: 1 z: 8 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Repetitive" | 1 | display_name: "The Repetitive" |
| 2 | rte_room: "Main Room" | 2 | rte_room: "Main Room" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 35.5 } | ||
| 4 | rte_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. |
| 4 | excluded_nodes: "Meshes/eyeRed3" | 6 | excluded_nodes: "Meshes/eyeRed3" |
| 5 | excluded_nodes: "Meshes/eyeRed4" | 7 | excluded_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 @@ | |||
| 1 | display_name: "The Revitalized" | 1 | display_name: "The Revitalized" |
| 2 | rte_room: "Bye Room" | 2 | rte_room: "Bye Room" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_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). |
| 4 | excluded_nodes: "Components/panel_demo" | 6 | excluded_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 @@ | |||
| 1 | display_name: "The Shop" | 1 | display_name: "The Shop" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 0.5 y: 0 z: -12 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Sirenic" | 1 | display_name: "The Sirenic" |
| 2 | rte_room: "Start" | 2 | rte_room: "Start" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 23 } | ||
| 4 | rte_trigger_scale { x: 6 y: 1 z: 4 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Stellar" | 1 | display_name: "The Stellar" |
| 2 | type: GIFT_MAP | 2 | type: GIFT_MAP |
| 3 | rte_room: "Starting Room" | 3 | rte_room: "Starting Room" |
| 4 | rte_trigger_pos { x: 0 y: 0 z: -3 } | ||
| 5 | rte_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. |
| 5 | excluded_nodes: "Panels/Room_1/panel_2" | 7 | excluded_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 @@ | |||
| 1 | display_name: "The Stormy" | 1 | display_name: "The Stormy" |
| 2 | rte_room: "Center" | 2 | rte_room: "Center" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Sturdy" | 1 | display_name: "The Sturdy" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 2 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Sun Temple" | 1 | display_name: "The Sun Temple" |
| 2 | rte_room: "Entrance" | 2 | rte_room: "Entrance" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 2 } | ||
| 4 | rte_trigger_scale { x: 10 y: 1 z: 10 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Sweet" | 1 | display_name: "The Sweet" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: -14.5 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Symbolic" | 1 | display_name: "The Symbolic" |
| 2 | rte_room: "White Room" | 2 | rte_room: "White Room" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_trigger_scale { x: 6 y: 1 z: 6 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Talented" | 1 | display_name: "The Talented" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 9 } | ||
| 4 | rte_trigger_scale { x: 6 y: 1 z: 15 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Tenacious" | 1 | display_name: "The Tenacious" |
| 2 | rte_room: "Control Center Entrance" | 2 | rte_room: "Control Center Entrance" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 10 } | ||
| 4 | rte_trigger_scale { x: 4 y: 1 z: 4 } | ||
| 3 | daedalus_only_mode: DAED_ONLY_ALLOW | 5 | daedalus_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 @@ | |||
| 1 | display_name: "The Three Doors" | 1 | display_name: "The Three Doors" |
| 2 | rte_room: "First Second Room" | 2 | rte_room: "First Second Room" |
| 3 | rte_trigger_pos { x: -15 y: 0 z: 1 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Tower" | 1 | display_name: "The Tower" |
| 2 | rte_room: "First Floor" | 2 | rte_room: "First Floor" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_trigger_scale { x: 8 y: 1 z: 8 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Tree" | 1 | display_name: "The Tree" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Unkempt" | 1 | display_name: "The Unkempt" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: -12 y: 0 z: -2 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Unyielding" | 1 | display_name: "The Unyielding" |
| 2 | rte_room: "Digital Entrance" | 2 | rte_room: "Digital Entrance" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: -6 } | ||
| 4 | rte_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 @@ | |||
| 1 | display_name: "The Wise" | 1 | display_name: "The Wise" |
| 2 | rte_room: "Entry" | 2 | rte_room: "Entry" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 22.5 } | ||
| 4 | rte_trigger_scale { x: 6 y: 1 z: 6 } | ||
| 3 | # This port is out of bounds. | 5 | # This port is out of bounds. |
| 4 | excluded_nodes: "Components/Warps/worldport" | 6 | excluded_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 @@ | |||
| 1 | display_name: "The Wondrous" | 1 | display_name: "The Wondrous" |
| 2 | rte_room: "Entry" | 2 | rte_room: "Entry" |
| 3 | rte_trigger_pos { x: 8 y: 0 z: 40 } | ||
| 4 | rte_trigger_scale { x: 6 y: 1 z: 6 } | ||
| 3 | worldport_entrance { | 5 | worldport_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 @@ | |||
| 1 | display_name: "The Words" | 1 | display_name: "The Words" |
| 2 | rte_room: "Main Area" | 2 | rte_room: "Main Area" |
| 3 | rte_trigger_pos { x: 0 y: 0 z: 0 } | ||
| 4 | rte_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. |
| 5 | excluded_nodes: "Panels/Proxies/panel_3" | 7 | excluded_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 @@ | |||
| 1 | version { | 1 | version { |
| 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. |
| 7 | special_names: "A Job Well Done" | 7 | special_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 | ||
| 296 | message Progressive { | 299 | message 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()); |
