about summary refs log tree commit diff stats
path: root/apworld/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'apworld/__init__.py')
-rw-r--r--apworld/__init__.py57
1 files changed, 51 insertions, 6 deletions
diff --git a/apworld/__init__.py b/apworld/__init__.py index 2213e33..3d2f075 100644 --- a/apworld/__init__.py +++ b/apworld/__init__.py
@@ -1,14 +1,18 @@
1""" 1"""
2Archipelago init file for Lingo 2 2Archipelago init file for Lingo 2
3""" 3"""
4from typing import ClassVar
5
4from BaseClasses import ItemClassification, Item, Tutorial 6from BaseClasses import ItemClassification, Item, Tutorial
7from Options import OptionError
8from settings import Group, UserFilePath
5from worlds.AutoWorld import WebWorld, World 9from worlds.AutoWorld import WebWorld, World
6from .items import Lingo2Item, ANTI_COLLECTABLE_TRAPS 10from .items import Lingo2Item, ANTI_COLLECTABLE_TRAPS
7from .options import Lingo2Options 11from .options import Lingo2Options
8from .player_logic import Lingo2PlayerLogic 12from .player_logic import Lingo2PlayerLogic
9from .regions import create_regions, shuffle_entrances, connect_ports_from_ut 13from .regions import create_regions, shuffle_entrances, connect_ports_from_ut
10from .static_logic import Lingo2StaticLogic 14from .static_logic import Lingo2StaticLogic
11from .version import APWORLD_VERSION 15from worlds.LauncherComponents import Component, Type, components, launch as launch_component, icon_paths
12 16
13 17
14class Lingo2WebWorld(WebWorld): 18class Lingo2WebWorld(WebWorld):
@@ -24,6 +28,15 @@ class Lingo2WebWorld(WebWorld):
24 )] 28 )]
25 29
26 30
31class Lingo2Settings(Group):
32 class ExecutableFile(UserFilePath):
33 """Path to the Lingo 2 executable"""
34 is_exe = True
35
36 exe_file: ExecutableFile = ExecutableFile()
37 start_game: bool = True
38
39
27class Lingo2World(World): 40class Lingo2World(World):
28 """ 41 """
29 Lingo 2 is a first person indie puzzle game where you solve word puzzles in a labyrinthe world. Compared to its 42 Lingo 2 is a first person indie puzzle game where you solve word puzzles in a labyrinthe world. Compared to its
@@ -33,6 +46,9 @@ class Lingo2World(World):
33 game = "Lingo 2" 46 game = "Lingo 2"
34 web = Lingo2WebWorld() 47 web = Lingo2WebWorld()
35 48
49 settings: ClassVar[Lingo2Settings]
50 settings_key = "lingo2_options"
51
36 topology_present = True 52 topology_present = True
37 53
38 options_dataclass = Lingo2Options 54 options_dataclass = Lingo2Options
@@ -44,6 +60,8 @@ class Lingo2World(World):
44 item_name_groups = static_logic.item_name_groups 60 item_name_groups = static_logic.item_name_groups
45 location_name_groups = static_logic.location_name_groups 61 location_name_groups = static_logic.location_name_groups
46 62
63 for_tracker: ClassVar[bool] = False
64
47 player_logic: Lingo2PlayerLogic 65 player_logic: Lingo2PlayerLogic
48 66
49 port_pairings: dict[int, int] 67 port_pairings: dict[int, int]
@@ -59,15 +77,18 @@ class Lingo2World(World):
59 if self.options.shuffle_worldports: 77 if self.options.shuffle_worldports:
60 if hasattr(self.multiworld, "re_gen_passthrough") and "Lingo 2" in self.multiworld.re_gen_passthrough: 78 if hasattr(self.multiworld, "re_gen_passthrough") and "Lingo 2" in self.multiworld.re_gen_passthrough:
61 slot_value = self.multiworld.re_gen_passthrough["Lingo 2"]["port_pairings"] 79 slot_value = self.multiworld.re_gen_passthrough["Lingo 2"]["port_pairings"]
62 self.port_pairings = {int(fp): int(tp) for fp, tp in slot_value.items()} 80 self.port_pairings = {
81 self.static_logic.port_id_by_ap_id[int(fp)]: self.static_logic.port_id_by_ap_id[int(tp)]
82 for fp, tp in slot_value.items()
83 }
63 84
64 connect_ports_from_ut(self.port_pairings, self) 85 connect_ports_from_ut(self.port_pairings, self)
65 else: 86 else:
66 shuffle_entrances(self) 87 shuffle_entrances(self)
67 88
68 from Utils import visualize_regions 89 #from Utils import visualize_regions
69 90
70 visualize_regions(self.multiworld.get_region("Menu", self.player), "my_world.puml") 91 #visualize_regions(self.multiworld.get_region("Menu", self.player), "my_world.puml")
71 92
72 def create_items(self): 93 def create_items(self):
73 pool = [self.create_item(name) for name in self.player_logic.real_items] 94 pool = [self.create_item(name) for name in self.player_logic.real_items]
@@ -92,6 +113,11 @@ class Lingo2World(World):
92 for i in range(0, item_difference): 113 for i in range(0, item_difference):
93 pool.append(self.create_item(self.get_filler_item_name())) 114 pool.append(self.create_item(self.get_filler_item_name()))
94 115
116 if not any(ItemClassification.progression in item.classification for item in pool):
117 raise OptionError(f"Lingo 2 player {self.player} has no progression items. Please enable at least one "
118 f"option that would add progression gating to your world, such as Shuffle Doors or "
119 f"Shuffle Letters.")
120
95 self.multiworld.itempool += pool 121 self.multiworld.itempool += pool
96 122
97 def create_item(self, name: str) -> Item: 123 def create_item(self, name: str) -> Item:
@@ -107,7 +133,11 @@ class Lingo2World(World):
107 slot_options = [ 133 slot_options = [
108 "cyan_door_behavior", 134 "cyan_door_behavior",
109 "daedalus_roof_access", 135 "daedalus_roof_access",
136 "enable_gift_maps",
137 "enable_icarus",
138 "endings_requirement",
110 "keyholder_sanity", 139 "keyholder_sanity",
140 "masteries_requirement",
111 "shuffle_control_center_colors", 141 "shuffle_control_center_colors",
112 "shuffle_doors", 142 "shuffle_doors",
113 "shuffle_gallery_paintings", 143 "shuffle_gallery_paintings",
@@ -121,11 +151,15 @@ class Lingo2World(World):
121 151
122 slot_data: dict[str, object] = { 152 slot_data: dict[str, object] = {
123 **self.options.as_dict(*slot_options), 153 **self.options.as_dict(*slot_options),
124 "version": [self.static_logic.get_data_version(), APWORLD_VERSION], 154 "version": self.static_logic.get_data_version(),
125 } 155 }
126 156
127 if self.options.shuffle_worldports: 157 if self.options.shuffle_worldports:
128 slot_data["port_pairings"] = self.port_pairings 158 def get_port_ap_id(port_id):
159 return self.static_logic.objects.ports[port_id].ap_id
160
161 slot_data["port_pairings"] = {get_port_ap_id(from_id): get_port_ap_id(to_id)
162 for from_id, to_id in self.port_pairings.items()}
129 163
130 return slot_data 164 return slot_data
131 165
@@ -139,3 +173,14 @@ class Lingo2World(World):
139 # returning slot_data so it regens, giving it back in multiworld.re_gen_passthrough 173 # returning slot_data so it regens, giving it back in multiworld.re_gen_passthrough
140 # we are using re_gen_passthrough over modifying the world here due to complexities with ER 174 # we are using re_gen_passthrough over modifying the world here due to complexities with ER
141 return slot_data 175 return slot_data
176
177
178def launch_client(*args):
179 from .context import client_main
180 launch_component(client_main, name="Lingo2Client", args=args)
181
182
183icon_paths["lingo2_ico"] = f"ap:{__name__}/logo.png"
184component = Component("Lingo 2 Client", component_type=Type.CLIENT, func=launch_client,
185 description="Open Lingo 2.", supports_uri=True, game_name="Lingo 2", icon="lingo2_ico")
186components.append(component)