Skip to content

Commit 9ea90cb

Browse files
Merge branch 'ArchipelagoMW:main' into tunic-randomizer
2 parents 473d82d + eb50e07 commit 9ea90cb

22 files changed

+262
-53
lines changed

BaseClasses.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -487,8 +487,10 @@ def get_placeable_locations(self, state=None, player=None) -> List[Location]:
487487
def get_unfilled_locations_for_players(self, location_names: List[str], players: Iterable[int]):
488488
for player in players:
489489
if not location_names:
490-
location_names = [location.name for location in self.get_unfilled_locations(player)]
491-
for location_name in location_names:
490+
valid_locations = [location.name for location in self.get_unfilled_locations(player)]
491+
else:
492+
valid_locations = location_names
493+
for location_name in valid_locations:
492494
location = self._location_cache.get((location_name, player), None)
493495
if location is not None and location.item is None:
494496
yield location

Fill.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ def fill_restrictive(world: MultiWorld, base_state: CollectionState, locations:
5151
items_to_place = [items.pop()
5252
for items in reachable_items.values() if items]
5353
for item in items_to_place:
54-
item_pool.remove(item)
54+
for p, pool_item in enumerate(item_pool):
55+
if pool_item is item:
56+
item_pool.pop(p)
57+
break
5558
maximum_exploration_state = sweep_from_pool(
5659
base_state, item_pool + unplaced_items)
5760

MultiServer.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -2118,13 +2118,15 @@ def attrtype(input_text: str):
21182118
async def console(ctx: Context):
21192119
import sys
21202120
queue = asyncio.Queue()
2121-
Utils.stream_input(sys.stdin, queue)
2121+
worker = Utils.stream_input(sys.stdin, queue)
21222122
while not ctx.exit_event.is_set():
21232123
try:
21242124
# I don't get why this while loop is needed. Works fine without it on clients,
21252125
# but the queue.get() for server never fulfills if the queue is empty when entering the await.
21262126
while queue.qsize() == 0:
21272127
await asyncio.sleep(0.05)
2128+
if not worker.is_alive():
2129+
return
21282130
input_text = await queue.get()
21292131
queue.task_done()
21302132
ctx.commandprocessor(input_text)

Options.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,7 @@ def verify(self, world: typing.Type[World], player_name: str, plando_options: "P
771771
f"Did you mean '{picks[0][0]}' ({picks[0][1]}% sure)")
772772

773773

774-
class OptionDict(Option[typing.Dict[str, typing.Any]], VerifyKeys):
774+
class OptionDict(Option[typing.Dict[str, typing.Any]], VerifyKeys, typing.Mapping[str, typing.Any]):
775775
default: typing.Dict[str, typing.Any] = {}
776776
supports_weighting = False
777777

@@ -789,8 +789,14 @@ def from_any(cls, data: typing.Dict[str, typing.Any]) -> OptionDict:
789789
def get_option_name(self, value):
790790
return ", ".join(f"{key}: {v}" for key, v in value.items())
791791

792-
def __contains__(self, item):
793-
return item in self.value
792+
def __getitem__(self, item: str) -> typing.Any:
793+
return self.value.__getitem__(item)
794+
795+
def __iter__(self) -> typing.Iterator[str]:
796+
return self.value.__iter__()
797+
798+
def __len__(self) -> int:
799+
return self.value.__len__()
794800

795801

796802
class ItemDict(OptionDict):

PokemonClient.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,10 @@ async def parse_locations(data: List, ctx: GBContext):
176176
elif (location_name_to_id["Fossil - Choice B"] in ctx.checked_locations and location_name_to_id["Fossil - Choice A"]
177177
not in ctx.checked_locations):
178178
hints.append("Fossil - Choice A")
179-
hints = [location_name_to_id[loc] for loc in hints if loc not in ctx.auto_hints and location_name_to_id[loc] in
180-
ctx.missing_locations and location_name_to_id[loc] not in ctx.locations_checked]
179+
hints = [
180+
location_name_to_id[loc] for loc in hints if location_name_to_id[loc] not in ctx.auto_hints and
181+
location_name_to_id[loc] in ctx.missing_locations and location_name_to_id[loc] not in ctx.locations_checked
182+
]
181183
if hints:
182184
await ctx.send_msgs([{"cmd": "LocationScouts", "locations": hints, "create_as_hint": 2}])
183185
ctx.auto_hints.update(hints)

_speedups.pyx

+8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ from libc.stdint cimport int64_t, uint32_t
1616
from libcpp.set cimport set as std_set
1717
from collections import defaultdict
1818

19+
cdef extern from *:
20+
"""
21+
// avoid warning from cython-generated code with MSVC + pyximport
22+
#ifdef _MSC_VER
23+
#pragma warning( disable: 4551 )
24+
#endif
25+
"""
26+
1927
ctypedef uint32_t ap_player_t # on AMD64 this is faster (and smaller) than 64bit ints
2028
ctypedef uint32_t ap_flags_t
2129
ctypedef int64_t ap_id_t

test/general/TestFill.py

+14
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,20 @@ def test_double_sweep(self):
433433
self.assertTrue(multi_world.state.prog_items[item.name, item.player], "Sweep did not collect - Test flawed")
434434
self.assertEqual(multi_world.state.prog_items[item.name, item.player], 1, "Sweep collected multiple times")
435435

436+
def test_correct_item_instance_removed_from_pool(self):
437+
multi_world = generate_multi_world()
438+
player1 = generate_player_data(multi_world, 1, 2, 2)
439+
440+
player1.prog_items[0].name = "Different_item_instance_but_same_item_name"
441+
player1.prog_items[1].name = "Different_item_instance_but_same_item_name"
442+
loc0 = player1.locations[0]
443+
444+
fill_restrictive(multi_world, multi_world.state,
445+
[loc0], player1.prog_items)
446+
447+
self.assertEqual(1, len(player1.prog_items))
448+
self.assertIsNot(loc0.item, player1.prog_items[0], "Filled item was still present in item pool")
449+
436450

437451
class TestDistributeItemsRestrictive(unittest.TestCase):
438452
def test_basic_distribute(self):

worlds/alttp/__init__.py

+26
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,32 @@ def get_pre_fill_items(self):
782782
res.append(item)
783783
return res
784784

785+
def fill_slot_data(self):
786+
slot_data = {}
787+
if not self.multiworld.is_race:
788+
# all of these option are NOT used by the SNI- or Text-Client.
789+
# they are used by the alttp-poptracker pack (https://github.com/StripesOO7/alttp-ap-poptracker-pack)
790+
# for convenient auto-tracking of the generated settings and adjusting the tracker accordingly
791+
792+
slot_options = ["crystals_needed_for_gt", "crystals_needed_for_ganon", "open_pyramid",
793+
"bigkey_shuffle", "smallkey_shuffle", "compass_shuffle", "map_shuffle",
794+
"progressive", "swordless", "retro_bow", "retro_caves", "shop_item_slots",
795+
"boss_shuffle", "pot_shuffle", "enemy_shuffle"]
796+
797+
slot_data = {option_name: getattr(self.multiworld, option_name)[self.player].value for option_name in slot_options}
798+
799+
slot_data.update({
800+
'mode': self.multiworld.mode[self.player],
801+
'goal': self.multiworld.goal[self.player],
802+
'dark_room_logic': self.multiworld.dark_room_logic[self.player],
803+
'mm_medalion': self.multiworld.required_medallions[self.player][0],
804+
'tr_medalion': self.multiworld.required_medallions[self.player][1],
805+
'shop_shuffle': self.multiworld.shop_shuffle[self.player],
806+
'entrance_shuffle': self.multiworld.shuffle[self.player]
807+
}
808+
)
809+
return slot_data
810+
785811

786812
def get_same_seed(world, seed_def: tuple) -> str:
787813
seeds: typing.Dict[tuple, str] = getattr(world, "__named_seeds", {})

worlds/dkc3/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -216,5 +216,8 @@ def create_item(self, name: str, force_non_progression=False) -> Item:
216216

217217
return created_item
218218

219+
def get_filler_item_name(self) -> str:
220+
return self.multiworld.random.choice(list(junk_table.keys()))
221+
219222
def set_rules(self):
220223
set_rules(self.multiworld, self.player)

worlds/dlcquest/Rules.py

+2
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ def set_basic_shuffled_items_rules(World_Options, player, world):
105105
lambda state: state.has("Sword", player) or state.has("Gun", player))
106106
set_rule(world.get_location("West Cave Sheep", player),
107107
lambda state: state.has("Sword", player) or state.has("Gun", player))
108+
set_rule(world.get_location("Gun", player),
109+
lambda state: state.has("Gun Pack", player))
108110

109111
if World_Options[Options.TimeIsMoney] == Options.TimeIsMoney.option_required:
110112
set_rule(world.get_location("Sword", player),

worlds/doom_1993/Options.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class Episode3(DefaultOnToggle):
8080
display_name = "Episode 3"
8181

8282

83-
class Episode4(DefaultOnToggle):
83+
class Episode4(Toggle):
8484
"""Thy Flesh Consumed.
8585
If none of the episodes are chosen, Episode 1 will be chosen by default."""
8686
display_name = "Episode 4"

0 commit comments

Comments
 (0)