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