diff options
Diffstat (limited to 'apworld/tracker.py')
-rw-r--r-- | apworld/tracker.py | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/apworld/tracker.py b/apworld/tracker.py index 721e9b3..2c3d0f3 100644 --- a/apworld/tracker.py +++ b/apworld/tracker.py | |||
@@ -1,14 +1,22 @@ | |||
1 | from typing import TYPE_CHECKING | ||
2 | |||
1 | from BaseClasses import MultiWorld, CollectionState, ItemClassification | 3 | from BaseClasses import MultiWorld, CollectionState, ItemClassification |
2 | from NetUtils import NetworkItem | 4 | from NetUtils import NetworkItem |
3 | from . import Lingo2World, Lingo2Item | 5 | from . import Lingo2World, Lingo2Item |
4 | from .regions import connect_ports_from_ut | 6 | from .regions import connect_ports_from_ut |
5 | from .options import Lingo2Options | 7 | from .options import Lingo2Options, ShuffleLetters |
8 | |||
9 | if TYPE_CHECKING: | ||
10 | from .context import Lingo2Manager | ||
6 | 11 | ||
7 | PLAYER_NUM = 1 | 12 | PLAYER_NUM = 1 |
8 | 13 | ||
9 | 14 | ||
10 | class Tracker: | 15 | class Tracker: |
16 | manager: "Lingo2Manager" | ||
17 | |||
11 | multiworld: MultiWorld | 18 | multiworld: MultiWorld |
19 | world: Lingo2World | ||
12 | 20 | ||
13 | collected_items: dict[int, int] | 21 | collected_items: dict[int, int] |
14 | checked_locations: set[int] | 22 | checked_locations: set[int] |
@@ -16,26 +24,29 @@ class Tracker: | |||
16 | 24 | ||
17 | state: CollectionState | 25 | state: CollectionState |
18 | 26 | ||
19 | def __init__(self): | 27 | def __init__(self, manager: "Lingo2Manager"): |
28 | self.manager = manager | ||
20 | self.collected_items = {} | 29 | self.collected_items = {} |
21 | self.checked_locations = set() | 30 | self.checked_locations = set() |
22 | self.accessible_locations = set() | 31 | self.accessible_locations = set() |
23 | 32 | ||
24 | def setup_slot(self, slot_data): | 33 | def setup_slot(self, slot_data): |
34 | Lingo2World.for_tracker = True | ||
35 | |||
25 | self.multiworld = MultiWorld(players=PLAYER_NUM) | 36 | self.multiworld = MultiWorld(players=PLAYER_NUM) |
26 | world = Lingo2World(self.multiworld, PLAYER_NUM) | 37 | self.world = Lingo2World(self.multiworld, PLAYER_NUM) |
27 | self.multiworld.worlds[1] = world | 38 | self.multiworld.worlds[1] = self.world |
28 | world.options = Lingo2Options(**{k: t(slot_data.get(k, t.default)) | 39 | self.world.options = Lingo2Options(**{k: t(slot_data.get(k, t.default)) |
29 | for k, t in Lingo2Options.type_hints.items()}) | 40 | for k, t in Lingo2Options.type_hints.items()}) |
30 | 41 | ||
31 | world.generate_early() | 42 | self.world.generate_early() |
32 | world.create_regions() | 43 | self.world.create_regions() |
33 | 44 | ||
34 | if world.options.shuffle_worldports: | 45 | if self.world.options.shuffle_worldports: |
35 | port_pairings = {int(fp): int(tp) for fp, tp in slot_data["port_pairings"].items()} | 46 | port_pairings = {int(fp): int(tp) for fp, tp in slot_data["port_pairings"].items()} |
36 | connect_ports_from_ut(port_pairings, world) | 47 | connect_ports_from_ut(port_pairings, self.world) |
37 | 48 | ||
38 | self.state = CollectionState(self.multiworld) | 49 | self.refresh_state() |
39 | 50 | ||
40 | def set_checked_locations(self, checked_locations: set[int]): | 51 | def set_checked_locations(self, checked_locations: set[int]): |
41 | self.checked_locations = checked_locations.copy() | 52 | self.checked_locations = checked_locations.copy() |
@@ -56,6 +67,23 @@ class Tracker: | |||
56 | self.state.collect(Lingo2Item(Lingo2World.static_logic.item_id_to_name.get(item_id), | 67 | self.state.collect(Lingo2Item(Lingo2World.static_logic.item_id_to_name.get(item_id), |
57 | ItemClassification.progression, item_id, PLAYER_NUM), prevent_sweep=True) | 68 | ItemClassification.progression, item_id, PLAYER_NUM), prevent_sweep=True) |
58 | 69 | ||
70 | for k, v in self.manager.keyboard.items(): | ||
71 | # Unless all level 1 letters are pre-unlocked, H1 I1 N1 and T1 act differently between the generator and | ||
72 | # game. The generator considers them to be unlocked, which means they are not included in logic | ||
73 | # requirements, and only one item/event is needed to unlock their level 2 forms. The game considers them to | ||
74 | # be vanilla, which means you still have to pick them up in the Starting Room in order for them to appear on | ||
75 | # your keyboard. This also means that whether or not you have the level 1 forms should be synced to the | ||
76 | # multiworld. The tracker specifically should collect one fewer item for these letters in this scenario. | ||
77 | tv = v | ||
78 | if k in "hint" and self.world.options.shuffle_letters in [ShuffleLetters.option_vanilla, | ||
79 | ShuffleLetters.option_progressive]: | ||
80 | tv = max(0, v - 1) | ||
81 | |||
82 | if tv > 0: | ||
83 | for i in range(tv): | ||
84 | self.state.collect(Lingo2Item(k.upper(), ItemClassification.progression, None, PLAYER_NUM), | ||
85 | prevent_sweep=True) | ||
86 | |||
59 | self.state.sweep_for_advancements() | 87 | self.state.sweep_for_advancements() |
60 | 88 | ||
61 | self.accessible_locations = set() | 89 | self.accessible_locations = set() |