about summary refs log tree commit diff stats
path: root/apworld/tracker.py
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2025-09-27 17:14:40 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2025-09-27 17:14:40 -0400
commitb0f474bee1c8e1111f7542bf4985136d9aedf340 (patch)
treeef2aa34bad532ffb2a45d90893dbcd4c378a0dfb /apworld/tracker.py
parentfeb89a44ddf5f93bc476ca29cd02257aea47dc06 (diff)
downloadlingo2-archipelago-b0f474bee1c8e1111f7542bf4985136d9aedf340.tar.gz
lingo2-archipelago-b0f474bee1c8e1111f7542bf4985136d9aedf340.tar.bz2
lingo2-archipelago-b0f474bee1c8e1111f7542bf4985136d9aedf340.zip
Treat local letters as items for tracker
Local letters are now synced with datastorage, so they transfer to other computers like regular items would, and the tracker also now waits until you collect local letters before showing what they give you in logic.
Diffstat (limited to 'apworld/tracker.py')
-rw-r--r--apworld/tracker.py50
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 @@
1from typing import TYPE_CHECKING
2
1from BaseClasses import MultiWorld, CollectionState, ItemClassification 3from BaseClasses import MultiWorld, CollectionState, ItemClassification
2from NetUtils import NetworkItem 4from NetUtils import NetworkItem
3from . import Lingo2World, Lingo2Item 5from . import Lingo2World, Lingo2Item
4from .regions import connect_ports_from_ut 6from .regions import connect_ports_from_ut
5from .options import Lingo2Options 7from .options import Lingo2Options, ShuffleLetters
8
9if TYPE_CHECKING:
10 from .context import Lingo2Manager
6 11
7PLAYER_NUM = 1 12PLAYER_NUM = 1
8 13
9 14
10class Tracker: 15class 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()