From 7a0606dd10dbd256675bff35ebd8a7957a3607e8 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Sun, 8 Feb 2026 12:10:19 -0500 Subject: Added custom mint ending --- apworld/__init__.py | 1 + apworld/client/manager.gd | 2 ++ apworld/client/maps/control_center.gd | 33 +++++++++++++++++++++++++++++++++ apworld/options.py | 12 +++++++++++- apworld/player_logic.py | 8 ++++++++ apworld/regions.py | 4 ++++ 6 files changed, 59 insertions(+), 1 deletion(-) (limited to 'apworld') diff --git a/apworld/__init__.py b/apworld/__init__.py index a80156c..6b5338e 100644 --- a/apworld/__init__.py +++ b/apworld/__init__.py @@ -167,6 +167,7 @@ class Lingo2World(World): slot_data: dict[str, object] = { **self.options.as_dict(*slot_options), + "custom_mint_ending": self.player_logic.custom_mint_ending or "", "rte": [self.static_logic.objects.maps[map_id].name for map_id in self.player_logic.rte_mapping], "seed": self.random.randint(0, 1000000), "version": self.static_logic.get_data_version(), diff --git a/apworld/client/manager.gd b/apworld/client/manager.gd index e259708..f10a0b7 100644 --- a/apworld/client/manager.gd +++ b/apworld/client/manager.gd @@ -67,6 +67,7 @@ const kEndingNameByVictoryValue = { } var apworld_version = [0, 0, 0] +var custom_mint_ending = "" var cyan_door_behavior = kCYAN_DOOR_BEHAVIOR_H2 var daedalus_only = false var daedalus_roof_access = false @@ -478,6 +479,7 @@ func _client_connected(slot_data): _last_new_item = localdata[0] # Read slot data. + custom_mint_ending = slot_data.get("custom_mint_ending", "") cyan_door_behavior = int(slot_data.get("cyan_door_behavior", 0)) daedalus_only = bool(slot_data.get("daedalus_only", false)) daedalus_roof_access = bool(slot_data.get("daedalus_roof_access", false)) diff --git a/apworld/client/maps/control_center.gd b/apworld/client/maps/control_center.gd index 1fecc7b..8e919ab 100644 --- a/apworld/client/maps/control_center.gd +++ b/apworld/client/maps/control_center.gd @@ -96,6 +96,39 @@ func on_map_load(root): sign2.text = "Masteries: %d/%d" % [mastery_count, ap.masteries_requirement] root.get_node("/root/scene").add_child.call_deferred(sign2) + # Handle custom Mint Ending. + if ap.custom_mint_ending != "": + var panel_prefab = preload("res://objects/nodes/panel.tscn") + var tpl_prefab = preload("res://objects/nodes/listeners/teleportListener.tscn") + + var mint_ending = root.get_node("/root/scene/Components/Endings/mint_ending") + + var mint_panel = panel_prefab.instantiate() + mint_panel.name = "mint_panel" + mint_panel.clue = ap.custom_mint_ending + mint_panel.symbol = "" + mint_panel.answer = ap.custom_mint_ending + mint_panel.position = Vector3(-63, 3, -29) + mint_panel.rotation_degrees = Vector3(-45, 90, 0) + root.get_node("/root/scene").add_child.call_deferred(mint_panel) + + var mint_tpl = tpl_prefab.instantiate() + mint_tpl.name = "mint_tpl" + mint_tpl.teleport_point = mint_ending.position + mint_tpl.teleport_rotate = mint_ending.rotation_degrees + mint_tpl.target_path = mint_ending + mint_tpl.senders.append(NodePath("/root/scene/mint_panel")) + root.get_node("/root/scene").add_child.call_deferred(mint_tpl) + + var mint_tpl2 = tpl_prefab.instantiate() + mint_tpl2.name = "mint_tpl2" + mint_tpl2.teleport_point = Vector3(0, -1000, 0) + mint_tpl2.target_path = mint_panel + mint_tpl2.senders.append(NodePath("/root/scene/mint_panel")) + root.get_node("/root/scene").add_child.call_deferred(mint_tpl2) + + mint_ending.position.y = -1000 + func _set_up_mastery_listener(root, name): var prefab = preload("res://objects/nodes/listeners/unlockReaderListener.tscn") diff --git a/apworld/options.py b/apworld/options.py index fb159e1..c1eab33 100644 --- a/apworld/options.py +++ b/apworld/options.py @@ -1,6 +1,6 @@ from dataclasses import dataclass -from Options import PerGameCommonOptions, Toggle, Choice, DefaultOnToggle, Range, OptionSet +from Options import PerGameCommonOptions, Toggle, Choice, DefaultOnToggle, Range, OptionSet, FreeText class ShuffleDoors(DefaultOnToggle): @@ -178,6 +178,15 @@ class DaedalusRoofAccess(Toggle): display_name = "Allow Daedalus Roof Access" +class CustomMintEnding(FreeText): + """ + If not blank, this will add a new panel that must be solved before collecting Mint Ending (EXIT in the Control + Center). The panel will only require typing the text provided for this option, which means the choice of letters + here has an impact on logic. + """ + display_name = "Custom Mint Ending" + + class StrictPurpleEnding(DefaultOnToggle): """ If enabled, the player will be required to have all purple (level 1) letters in order to get Purple Ending. @@ -280,6 +289,7 @@ class Lingo2Options(PerGameCommonOptions): enable_gift_maps: EnableGiftMaps daedalus_only: DaedalusOnly daedalus_roof_access: DaedalusRoofAccess + custom_mint_ending: CustomMintEnding strict_purple_ending: StrictPurpleEnding strict_cyan_ending: StrictCyanEnding victory_condition: VictoryCondition diff --git a/apworld/player_logic.py b/apworld/player_logic.py index 7bfd49f..ea74266 100644 --- a/apworld/player_logic.py +++ b/apworld/player_logic.py @@ -223,6 +223,7 @@ class Lingo2PlayerLogic: double_letter_amount: dict[str, int] goal_room_id: int rte_mapping: list[int] + custom_mint_ending: str | None def __init__(self, world: "Lingo2World"): self.world = world @@ -237,6 +238,7 @@ class Lingo2PlayerLogic: self.real_items = list() self.starting_items = list() self.double_letter_amount = dict() + self.custom_mint_ending = None def should_shuffle_map(game_map) -> bool | set[int]: if world.options.daedalus_only: @@ -302,6 +304,12 @@ class Lingo2PlayerLogic: raise OptionError(f"When Restrict Letter Placements is enabled and Shuffle Letters is set to Progressive, " f"both Shuffle Doors and Shuffle Symbols must be disabled (Player {world.player}).") + if world.options.custom_mint_ending.value != "": + self.custom_mint_ending = ''.join(filter(str.isalpha, world.options.custom_mint_ending.value)).lower() + + if len(self.custom_mint_ending) > 52: + raise OptionError(f"Custom Mint Ending should not be greater than 52 letters (Player {world.player}).") + maximum_masteries = 13 + len(world.options.enable_gift_maps.value) if world.options.enable_icarus: maximum_masteries += 1 diff --git a/apworld/regions.py b/apworld/regions.py index 076c143..3996153 100644 --- a/apworld/regions.py +++ b/apworld/regions.py @@ -141,6 +141,10 @@ def create_regions(world: "Lingo2World"): if connection.HasField("cyan_ending") and connection.cyan_ending and world.options.strict_cyan_ending: world.player_logic.add_solution_reqs(reqs, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz") + if (connection.HasField("mint_ending") and connection.mint_ending + and world.player_logic.custom_mint_ending is not None): + world.player_logic.add_solution_reqs(reqs, world.player_logic.custom_mint_ending) + reqs.simplify() reqs.remove_room(from_region) -- cgit 1.4.1