Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
183 commits
Select commit Hold shift + click to select a range
3ef3510
LADX: Remove copyrighted assets (#4935)
Apr 30, 2025
5f974b7
SM: Fix FakeROM instances sharing the same data dictionary (#4912)
Mysteryem Apr 30, 2025
611e1c2
SMW: v2.1 Feature Update (#4652)
PoryGone Apr 30, 2025
227f0bc
Pokemon Red/Blue: Convert to Procedure Patch (#4801)
Zunawe Apr 30, 2025
c46ee7c
TUNIC: Lock pre-placed filler to make the game play nicer with prog b…
ScipioWright Apr 30, 2025
6beaacb
Generate: Better yaml parsing error messaging (#4927)
qwint May 2, 2025
1031fc4
Factorio: remove FactorioClient executable (#4928)
Berserker66 May 2, 2025
2455f11
Options: Cleanup CommonOptions.as_dict (#4921)
alwaysintreble May 2, 2025
da0207f
Factorio: implement custom filler items (#4945)
Berserker66 May 2, 2025
68c350b
CommonClient: rip out old global name lookup (#4941)
Berserker66 May 2, 2025
f4690e2
CommonClient: remove Datapackage Version handling (#4487)
qwint May 2, 2025
83ed3c8
Core: always embed Archipelago (#4880)
Berserker66 May 3, 2025
9425f5b
Docs: Direct Mac users to Launcher.py (#4767)
Bicoloursnake May 3, 2025
1885dab
TWW: Documentation Cleanup (#4942)
tanjo3 May 4, 2025
fa2d779
Core: update certifi (#4954)
Berserker66 May 4, 2025
68e37b8
Factorio: client cleanup and prevent process bomb (#4882)
Berserker66 May 4, 2025
b2d2c8e
Stardew Valley: Add void mayo requirement for Goblin Problem quest (#…
Jouramie May 4, 2025
b217372
Core: Make Perfect Fuzzy Match Prioritize Casing (#4956)
Exempt-Medic May 5, 2025
b898b9d
The Messenger: fix indentation in setup guide (#4959)
alwaysintreble May 6, 2025
7bbe620
Terraria: Fix inaccessible Leading Landlord achievement when getfixed…
Seldom-SE May 6, 2025
a3aac3d
TUNIC: Entrance rando Direction Pairs + Decoupled (#3761)
ScipioWright May 6, 2025
c40214e
Docs: Minor Changes to apworld_dev_faq.md (#4947)
ScipioWright May 7, 2025
0ba9ee0
Docs: update line length in apworld faq doc (#4960)
qwint May 7, 2025
17bc184
TUNIC: Add Hidden all_random Option (#4635)
ScipioWright May 7, 2025
dffde64
Docs: add a "soft logic" question to apworld_dev_faq.md (#4953)
Ixrec May 7, 2025
1ee8e33
Launcher: Warn if there is no File Browser (#4275)
Zannick May 7, 2025
703f5a2
OSRS: New Tasks, New Options, Compatibility with new Plugin Features …
digiholic May 7, 2025
bcd7d62
LADX: Improve Fake Tracker Items (#4897)
kbranch May 7, 2025
b0f4246
MMBN3: Adds Beach Access to Help With Rehab Job Bonus Reward Check (#…
digiholic May 8, 2025
9a8abea
Add blurb about patch files to the host page (#4974)
palex00 May 9, 2025
cbfcaeb
Subnautica: use less multiworld API (#4977)
Berserker66 May 9, 2025
4e61f1f
Core: Institute limit of 10000 items on StartInventory (#4972)
NewSoupVi May 10, 2025
5f24da7
Core: Use the location of Utils.py rather than __main__ to determine…
silasary May 10, 2025
8f71dac
Stardew valley: Add Trap Distribution setting (#4601)
agilbert1412 May 10, 2025
68ed208
DS3: "US: Homeward Bone - foot, drop overlook" (#4875)
TVV1GK May 10, 2025
a166dc7
Core: Plando Items "Rewrite" (#3046)
Silvris May 10, 2025
53defd3
MultiServer: More Guardrails for Nolocation Clients (#4470)
qwint May 10, 2025
e809b93
The Messenger: do all empty state validation during portal shuffle (#…
alwaysintreble May 10, 2025
c0b3fa9
SMZ3: replace copyright credits music (#4978)
lordlou May 11, 2025
824caaf
Docs: clarify that ModuleUpdate.py is a prerequisite for running test…
Emerassi May 11, 2025
8340371
Muse Dash: Update to Otaku Pack Vol 20 (#4924)
DeamonHunter May 12, 2025
feaed7e
Docs: tests: add naming / file naming conventions (#4982)
black-sliver May 13, 2025
7d5693e
Stardew Valley: Move BaseTest out of `__init__.py` to comply with fut…
Jouramie May 13, 2025
0994afa
Tests: actually run tests in __init__.py files (#4969)
Ixrec May 13, 2025
b71c800
AHiT: Fix Client Argument Handling (#4992)
duckboycool May 14, 2025
72854cd
Docs: Add a "Missable Locations" Question to apworld FAQ (#4965)
Ixrec May 14, 2025
11842d3
DS3: Fix the Name of "Red and White Round Shield" (#4994)
nex3 May 14, 2025
a87fec0
SDV: Add Missing Marriage Requirement for Spouse Stardrop (#4988)
agilbert1412 May 14, 2025
02fd75c
Core: Update Some Outdated Typing (#4986)
nicholassaylor May 14, 2025
2a0d0b4
Noita: Modernization Refactor (#4980)
ScipioWright May 14, 2025
15e6383
lufia2ac: rearrange tests to comply with new conventions (#5001)
el-u May 15, 2025
90ee9ff
Stardew Valley: Remove Crab Pot Requirement for Help Wanted Fishing (…
Jouramie May 17, 2025
d3dbdb4
Kivy: Add a button prompt box (#3470)
alwaysintreble May 18, 2025
07664c4
SA2B: Logic Fixes (#5009)
PoryGone May 19, 2025
9ac628f
Terraria: remove 1.4.3-specific docs #5013
Seldom-SE May 20, 2025
485387e
ChecksFinder: Update setup guide (#4973)
SunCatMC May 20, 2025
e0d3101
Core: Remove redundant reachable location counting in swap (#4990)
Mysteryem May 20, 2025
9adbd40
Core: prepare worlds.Files for APWorldContainer (#4331)
Berserker66 May 20, 2025
feef0f4
Core: disable worlds_disabled (#5014)
Berserker66 May 20, 2025
f3e00b6
Zillion: fix `read_contents` to be compatible with base class (#5015)
beauxq May 20, 2025
7f4bf71
Adventure: Update AdventureDeltaPatch.read_contents to return the man…
NewSoupVi May 21, 2025
3069deb
Jak and Daxter: Implement New Game (#3291)
massimilianodelliubaldini May 21, 2025
d5bacab
shapez: Implement New Game (#3960)
BlastSlimey May 21, 2025
955a868
Super Mario Land 2: Implement New Game (#2730)
Alchav May 21, 2025
7e772b4
Raft: Small Raft doc update, bugfix (#5008)
SunnyBat May 21, 2025
a076b92
DS3: Don't make unrandomized items into events (#5018)
nex3 May 21, 2025
a409167
core: Reconfigure stdout to utf8 (#5017)
silasary May 21, 2025
6827368
Core: generate templates faster and "cleaner" (#5019)
Berserker66 May 21, 2025
defdf34
Wargroove: apworld (#4764)
FlySniper May 21, 2025
3b84500
core: don't reconfigure stdout if it's fake (#5020)
black-sliver May 21, 2025
7079c17
Wargroove: apworld doc fixes (#5023)
FlySniper May 22, 2025
e3219ba
WebHost: allow APPlayerContainers from "custom" worlds to be displaye…
Silvris May 22, 2025
b52310f
Wargroove: Cleanup `script_name` Component in `LauncherComponents` (#…
qwint May 22, 2025
e0918a7
TUNIC: Move some UT stuff out of init, put in UT poptracker integrati…
ScipioWright May 22, 2025
44a78cc
OoT: Stop Using Utils.get_options (#4957)
josephwhite May 22, 2025
95efcf6
Tests: Create CollectionState after MultiWorld.worlds (#4949)
qwint May 22, 2025
aeac83d
Generate: Don't Force Player Name for Weights Files (#4943)
alwaysintreble May 22, 2025
8cc6f10
The Messenger: Swap Options Docstrings to use rst, Add Option Groups …
alwaysintreble May 22, 2025
c5e768f
Minecraft: Stop Using Utils.get_options (#4879)
FlitPix May 22, 2025
1d655a0
Core: Add State add/remove/set Helpers (#4845)
alwaysintreble May 22, 2025
45e3027
The Messenger: Add a Component Icon and Description (#4850)
alwaysintreble May 22, 2025
402a8fb
AHiT: Add Dweller Mask Requirement to Normal Logic Rush Hour (#4499)
Mysteryem May 22, 2025
984df75
Stardew Valley: Move and Rework Monstersanity Tests (#4911)
Jouramie May 22, 2025
0351698
SDV: Fixed Import bases (#5025)
agilbert1412 May 22, 2025
88b5295
CommonClient: Add docs for Attributes (#5003)
qwint May 22, 2025
9c0ad2b
FF1: Bizhawk Client and APWorld Support (#4448)
Rosalie-A May 22, 2025
62694b1
Launcher: Fix on File Drop Error Message (#5026)
qwint May 22, 2025
653ee2b
Docs: Update Snippets to Modern Type Hints (#4987)
nicholassaylor May 22, 2025
de71677
Core: only raise min_client_version for new gens (#4896)
Berserker66 May 22, 2025
5491f8c
Core: Make `get_all_state` Sweeping Optional (#4828)
alwaysintreble May 23, 2025
e9f51e3
Linux: avoid adding cwd to LD_LIBRARY_PATH (#5029)
black-sliver May 23, 2025
a7de89f
shapez: Add game to README and CODEOWNERS (#5034)
BlastSlimey May 23, 2025
8671e9a
Stardew Valley: Make animal catalog logically year 2 (#5032)
Jouramie May 23, 2025
13ca134
Core: Fix a playthrough crash when a world uses "placement based logi…
NewSoupVi May 23, 2025
0a7aa9e
Launcher: skip launcher gui when opening webhost list with no game ha…
qwint May 23, 2025
e82d50a
The Messenger: more generous portal validation (#5011)
alwaysintreble May 23, 2025
c64791e
Stardew Valley: Replace current naive entrance rando with GER (#4624)
Jouramie May 24, 2025
47a0dd6
Stardew Valley: Added moss to statue of blessings recipe (#5038)
agilbert1412 May 24, 2025
704cd97
BizHawkClient: Fix script to list all cores instead of explicit mappi…
Zunawe May 24, 2025
e830a6d
TWW: Only add Filler for Excluded Locations Which are Progress Locati…
tanjo3 May 24, 2025
4119763
Lingo: Fix The Bearer's Pilgrimage Logic (#5005)
hatkirby May 24, 2025
eba757d
Raft: Implement get_filler_item_name and refactor filler item code a …
NewSoupVi May 24, 2025
e7545cb
SDV: Fixed Region for two Parrot Locations (#5042)
agilbert1412 May 24, 2025
f327ab3
CV64: Allow Holding Z to Use the Regular Shimmy Speed (#4730)
LiquidCat64 May 25, 2025
3248713
Core: Add descriptions to Components (#4849)
FlitPix May 25, 2025
002202f
Update OOT Guides (#5041)
ScootyPuffJr1 May 26, 2025
20ca7e7
TWW: Update patch class (#5046)
tanjo3 May 27, 2025
19a2109
Webhost: update Flask to 3.1.1 (#5052)
black-sliver May 27, 2025
fcb3efe
CVCotM: Add Nerf Roc Wing to Slot Data and HoD Max Ups to `other_game…
LiquidCat64 May 28, 2025
fde2033
Timespinner: Fix Logic (#4803)
Ehseezed May 28, 2025
dd6007b
TWW: Remove unnecessary items from slot data (#5045)
tanjo3 May 28, 2025
6ebd60f
Timespinner: Fix Logic Error with Risky Warp to Emperor's Tower and L…
sgrunt May 29, 2025
b0f41c0
Timespinner: Fix Connection Logic from Maw Cave Entrance to Maw (#4831)
sgrunt May 29, 2025
d19bf98
Jak and Daxter: Post-merge Polish (#5031)
massimilianodelliubaldini May 30, 2025
fab75d3
Stardew Valley: Fix Wizard Tower and Entrance Randomizer Softlocks (#…
Jouramie May 31, 2025
8f68bb3
Core and Various Worlds: define patch_file_ending to APPlayerContaine…
qwint Jun 2, 2025
cabde31
WebHost: Use expected APPlayerContainer manifest location directly wh…
qwint Jun 2, 2025
0c5cb17
DLCQuest: Add missing indirect conditions (#5074)
Mysteryem Jun 2, 2025
99142fd
Plando Items: Fix count with empty locations/location #5040
Exempt-Medic Jun 2, 2025
04c707f
DKC3: Add missing indirect conditions (#5073)
Mysteryem Jun 2, 2025
b85b18c
SoE: remove outdated info from guide (#5064)
black-sliver Jun 2, 2025
694e6bc
Launcher/Utils: reset LD_LIBRARY_PATH for system EXEs (#5022)
black-sliver Jun 3, 2025
a76cec1
TUNIC: Fix decoupled ER + ladder storage making invalid entrances #5075
ScipioWright Jun 3, 2025
b4f68bc
Factorio: revamp args parsing and passing (#5036)
Berserker66 Jun 3, 2025
603a500
DS3: Fix Non-Crow Itemlinking and Mark Aldrich Ruby and Twin Dragon G…
Exempt-Medic Jun 3, 2025
a2708ed
Timespinner: Fix Castle Ramparts Region Connection #5082
Ehseezed Jun 4, 2025
50db922
Timespinner: Fixed generation error because of timezone locking (#5084)
Jarno458 Jun 5, 2025
ab7d3ce
shapez: Remove preset unittests #5086
BlastSlimey Jun 5, 2025
f25ef63
Launcher: Fix Cli Components when installed to a directory with a spa…
qwint Jun 8, 2025
ddb3240
KH2: Give warning when client has cached locations (#5000)
JaredWeakStrike Jun 9, 2025
a8c87ce
CI: Add GH_REPO environment variable to labeler (#5081)
BadMagic100 Jun 10, 2025
52b1108
KH2: Raise Exception for Misusing DonaldGoofyStatsanity Option (#4710)
JaredWeakStrike Jun 11, 2025
aecbb2a
fix saving princess's use of subprocess helpers (#5103)
qwint Jun 13, 2025
8c6327d
LTTP/SDV: use .name when appropriate in subtests (#5107)
qwint Jun 13, 2025
0ad4527
SA2B: Logic Fixes (#5095)
PoryGone Jun 13, 2025
068a757
Item Plando: Fix `count` value (#5101)
Exempt-Medic Jun 14, 2025
e83e178
Stardew Valley: Fix 3 Logic Issues (#5094)
agilbert1412 Jun 14, 2025
2ff6111
ALTTP: Fix take_any leaving a placed item in the multiworld itempool …
NewSoupVi Jun 14, 2025
27a6770
Aquaria: Fixing open waters urns not breakable with nature forms logi…
tioui Jun 14, 2025
3b72140
Shivers: Fix get_pre_fill_items (#5113)
Exempt-Medic Jun 14, 2025
ecb739c
Plando Items: Fix Location Groups Unfolding (#5099)
Exempt-Medic Jun 14, 2025
aa9e617
DS3: Apply Rules to Non-Randomized Locations (#5106)
Exempt-Medic Jun 14, 2025
ec5b4e7
Plando Items: Better Warning for Nonexisting Worlds (#5112)
Exempt-Medic Jun 14, 2025
1356479
AdventureClient: Replace Utils.get_settings with settings.get_setting…
JusticePS Jun 15, 2025
b408bb4
Core: Docstring typo on Region.add_exits (#5089)
qwint Jun 16, 2025
0e759f2
Remove Minecraft (#4672)
KonoTyran Jun 16, 2025
377cdb8
MMBN3: Fixes Generation Errors and General UX Smoothing (#5077)
digiholic Jun 16, 2025
9246659
Make sure ladx removes the same copy of the starting item from the it…
NewSoupVi Jun 16, 2025
e0a63e0
DS3: Link to the Appropriate .NET Runtime for Proton (#5093)
nex3 Jun 16, 2025
dda5a05
shapez: Change Links to Shapesanity Cheat Sheet (#5047)
BlastSlimey Jun 16, 2025
5c710ad
Docs: Rework the "Events" Section of `world api.md` (#5012)
Ixrec Jun 16, 2025
47bf6d7
Minecraft Removal Cleanup (#5118)
Exempt-Medic Jun 16, 2025
6f244c4
Docs: Update Plando Guide and Make it More User Friendly (#4858)
massimilianodelliubaldini Jun 16, 2025
2114562
KDL3: update to gifting protocol 3 and update settings usage (#4814)
Silvris Jun 16, 2025
4eefd9c
Kivy: swap from the tab carousel to navigation bar (#4930)
alwaysintreble Jun 19, 2025
c2666ba
core: Don't attempt to write to the inside of an OSX App Bundle (#4380)
silasary Jun 19, 2025
e0ae335
Pokémon RB: Use new link for a new tracker (#5122)
palex00 Jun 20, 2025
c34e29c
Pokemon RB: Client: Send bounce messages with current map ID (#5121)
gerbiljames Jun 20, 2025
00f8625
Civilization VI: Updated setup and info pages (#5123)
DJ-lennart Jun 21, 2025
21864f6
CVCotM: Fix Advance Collection ROM (#5132)
LiquidCat64 Jun 27, 2025
5238973
TWW: Update Preset S7 to S8 (#5138)
tanjo3 Jun 27, 2025
da52598
Wargroove: Fix Communication Thread (#5125)
FlySniper Jun 27, 2025
03e5fd3
TWW: Fix Swords in Swordless Mode (#5137)
tanjo3 Jun 28, 2025
8aacc23
SDV: Add "Desert Transportation" and "Island Transportation" Item Gro…
Jouramie Jun 28, 2025
ba66ef1
Update world api.md (#5149)
ScipioWright Jul 2, 2025
1113003
Stardew Valley: Fixed luck level requirements for slot machines #5160
agilbert1412 Jul 3, 2025
072e2ec
Docs: 'get_prefill_items' -> 'get_pre_fill_items' (#5167)
Ixrec Jul 5, 2025
e68b1ad
CommonClient: fix extra panels added to `main_area_container` (#5151)
beauxq Jul 6, 2025
4623d59
Core: ensure slot_data and er_hint_info are only base data types (#5144)
Berserker66 Jul 7, 2025
95e09c8
Core: Take Counter back out of RestrictedUnpickler #5169
NewSoupVi Jul 7, 2025
d4ebace
[Jak and Daxter] Auto Detect Install Path after Game Launcher Update …
massimilianodelliubaldini Jul 7, 2025
f4b5422
Factorio: Fix link to world_gen documentation (#5171)
remyjette Jul 7, 2025
b1ff55d
DLCQ: Fix/Refactor LFoD Start Inventory (#5176)
axe-y Jul 10, 2025
edc0c89
CIV 6: Remove Erroneous Boost Prereqs for Computers Boost (#5134)
hesto2 Jul 10, 2025
2974f7d
Core: Replace Clique with V6 in unit tests (#5181)
NewSoupVi Jul 11, 2025
6af34b6
Various: Remove Rogue Legacy and Clique (#5177)
ThePhar Jul 11, 2025
7a6fb5e
Revert "Core: Take Counter back out of RestrictedUnpickler" (#5184)
NewSoupVi Jul 11, 2025
a794235
LADX: Update marin.txt (#5178)
Exempt-Medic Jul 11, 2025
909565e
Stardew Valley: Remove Rarecrow Locations from Night Market when Muse…
Jouramie Jul 12, 2025
585cbf9
TUNIC: Add UT Support for Breakables (#5182)
ScipioWright Jul 12, 2025
125d053
TUNIC: Fix missing line for UT stuff #5185
ScipioWright Jul 12, 2025
a9b35de
Muse Dash: Update song list to Rotaeno Update/7th Anniversary (#5066)
DeamonHunter Jul 12, 2025
ec3f168
Doc: match statement in style guide (#5187)
black-sliver Jul 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 0 additions & 1 deletion .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
- '!data/**'
- '!.run/**'
- '!.github/**'
- '!worlds_disabled/**'
- '!worlds/**'
- '!WebHost.py'
- '!WebHostLib/**'
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
shell: bash
run: |
cd build/exe*
cp Players/Templates/Clique.yaml Players/
cp Players/Templates/VVVVVV.yaml Players/
timeout 30 ./ArchipelagoGenerate
- name: Store 7z
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -189,7 +189,7 @@ jobs:
shell: bash
run: |
cd build/exe*
cp Players/Templates/Clique.yaml Players/
cp Players/Templates/VVVVVV.yaml Players/
timeout 30 ./ArchipelagoGenerate
- name: Store AppImage
uses: actions/upload-artifact@v4
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/label-pull-requests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ on:
permissions:
contents: read
pull-requests: write
env:
GH_REPO: ${{ github.repository }}

jobs:
labeler:
Expand Down
7 changes: 0 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ success.txt
output/
Output Logs/
/factorio/
/Minecraft Forge Server/
/WebHostLib/static/generated
/freeze_requirements.txt
/Archipelago.zip
Expand Down Expand Up @@ -184,12 +183,6 @@ _speedups.c
_speedups.cpp
_speedups.html

# minecraft server stuff
jdk*/
minecraft*/
minecraft_versions.json
!worlds/minecraft/

# pyenv
.python-version

Expand Down
3 changes: 2 additions & 1 deletion AHITClient.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import sys
from worlds.ahit.Client import launch
import Utils
import ModuleUpdate
ModuleUpdate.update()

if __name__ == "__main__":
Utils.init_logging("AHITClient", exception_logger="Client")
launch()
launch(*sys.argv[1:])
12 changes: 7 additions & 5 deletions AdventureClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@


import Utils
from settings import get_settings
from NetUtils import ClientStatus
from Utils import async_start
from CommonClient import CommonContext, server_loop, gui_enabled, ClientCommandProcessor, logger, \
Expand Down Expand Up @@ -80,8 +81,8 @@ def __init__(self, server_address, password):
self.local_item_locations = {}
self.dragon_speed_info = {}

options = Utils.get_settings()
self.display_msgs = options["adventure_options"]["display_msgs"]
options = get_settings().adventure_options
self.display_msgs = options.display_msgs

async def server_auth(self, password_requested: bool = False):
if password_requested and not self.password:
Expand All @@ -102,7 +103,7 @@ def _set_message(self, msg: str, msg_id: int):
def on_package(self, cmd: str, args: dict):
if cmd == 'Connected':
self.locations_array = None
if Utils.get_settings()["adventure_options"].get("death_link", False):
if get_settings().adventure_options.as_dict().get("death_link", False):
self.set_deathlink = True
async_start(self.get_freeincarnates_used())
elif cmd == "RoomInfo":
Expand Down Expand Up @@ -415,8 +416,9 @@ async def atari_sync_task(ctx: AdventureContext):


async def run_game(romfile):
auto_start = Utils.get_settings()["adventure_options"].get("rom_start", True)
rom_args = Utils.get_settings()["adventure_options"].get("rom_args")
options = get_settings().adventure_options
auto_start = options.rom_start
rom_args = options.rom_args
if auto_start is True:
import webbrowser
webbrowser.open(romfile)
Expand Down
108 changes: 80 additions & 28 deletions BaseClasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
from collections import Counter, deque
from collections.abc import Collection, MutableSequence
from enum import IntEnum, IntFlag
from typing import (AbstractSet, Any, Callable, ClassVar, Dict, Iterable, Iterator, List, Mapping, NamedTuple,
from typing import (AbstractSet, Any, Callable, ClassVar, Dict, Iterable, Iterator, List, Literal, Mapping, NamedTuple,
Optional, Protocol, Set, Tuple, Union, TYPE_CHECKING)
import dataclasses

from typing_extensions import NotRequired, TypedDict

Expand Down Expand Up @@ -54,12 +55,21 @@ class HasNameAndPlayer(Protocol):
player: int


@dataclasses.dataclass
class PlandoItemBlock:
player: int
from_pool: bool
force: bool | Literal["silent"]
worlds: set[int] = dataclasses.field(default_factory=set)
items: list[str] = dataclasses.field(default_factory=list)
locations: list[str] = dataclasses.field(default_factory=list)
resolved_locations: list[Location] = dataclasses.field(default_factory=list)
count: dict[str, int] = dataclasses.field(default_factory=dict)


class MultiWorld():
debug_types = False
player_name: Dict[int, str]
plando_texts: List[Dict[str, str]]
plando_items: List[List[Dict[str, Any]]]
plando_connections: List
worlds: Dict[int, "AutoWorld.World"]
groups: Dict[int, Group]
regions: RegionManager
Expand All @@ -83,6 +93,8 @@ class MultiWorld():
start_location_hints: Dict[int, Options.StartLocationHints]
item_links: Dict[int, Options.ItemLinks]

plando_item_blocks: Dict[int, List[PlandoItemBlock]]

game: Dict[int, str]

random: random.Random
Expand Down Expand Up @@ -160,13 +172,12 @@ def __init__(self, players: int):
self.local_early_items = {player: {} for player in self.player_ids}
self.indirect_connections = {}
self.start_inventory_from_pool: Dict[int, Options.StartInventoryPool] = {}
self.plando_item_blocks = {}

for player in range(1, players + 1):
def set_player_attr(attr: str, val) -> None:
self.__dict__.setdefault(attr, {})[player] = val
set_player_attr('plando_items', [])
set_player_attr('plando_texts', {})
set_player_attr('plando_connections', [])
set_player_attr('plando_item_blocks', [])
set_player_attr('game', "Archipelago")
set_player_attr('completion_condition', lambda state: True)
self.worlds = {}
Expand Down Expand Up @@ -427,7 +438,8 @@ def get_entrance(self, entrance_name: str, player: int) -> Entrance:
def get_location(self, location_name: str, player: int) -> Location:
return self.regions.location_cache[player][location_name]

def get_all_state(self, use_cache: bool, allow_partial_entrances: bool = False) -> CollectionState:
def get_all_state(self, use_cache: bool, allow_partial_entrances: bool = False,
collect_pre_fill_items: bool = True, perform_sweep: bool = True) -> CollectionState:
cached = getattr(self, "_all_state", None)
if use_cache and cached:
return cached.copy()
Expand All @@ -436,11 +448,13 @@ def get_all_state(self, use_cache: bool, allow_partial_entrances: bool = False)

for item in self.itempool:
self.worlds[item.player].collect(ret, item)
for player in self.player_ids:
subworld = self.worlds[player]
for item in subworld.get_pre_fill_items():
subworld.collect(ret, item)
ret.sweep_for_advancements()
if collect_pre_fill_items:
for player in self.player_ids:
subworld = self.worlds[player]
for item in subworld.get_pre_fill_items():
subworld.collect(ret, item)
if perform_sweep:
ret.sweep_for_advancements()

if use_cache:
self._all_state = ret
Expand Down Expand Up @@ -545,7 +559,9 @@ def has_beaten_game(self, state: CollectionState, player: Optional[int] = None)
else:
return all((self.has_beaten_game(state, p) for p in range(1, self.players + 1)))

def can_beat_game(self, starting_state: Optional[CollectionState] = None) -> bool:
def can_beat_game(self,
starting_state: Optional[CollectionState] = None,
locations: Optional[Iterable[Location]] = None) -> bool:
if starting_state:
if self.has_beaten_game(starting_state):
return True
Expand All @@ -554,7 +570,9 @@ def can_beat_game(self, starting_state: Optional[CollectionState] = None) -> boo
state = CollectionState(self)
if self.has_beaten_game(state):
return True
prog_locations = {location for location in self.get_locations() if location.item

base_locations = self.get_locations() if locations is None else locations
prog_locations = {location for location in base_locations if location.item
and location.item.advancement and location not in state.locations_checked}

while prog_locations:
Expand Down Expand Up @@ -723,6 +741,7 @@ class CollectionState():
additional_copy_functions: List[Callable[[CollectionState, CollectionState], CollectionState]] = []

def __init__(self, parent: MultiWorld, allow_partial_entrances: bool = False):
assert parent.worlds, "CollectionState created without worlds initialized in parent"
self.prog_items = {player: Counter() for player in parent.get_all_ids()}
self.multiworld = parent
self.reachable_regions = {player: set() for player in parent.get_all_ids()}
Expand Down Expand Up @@ -999,6 +1018,17 @@ def collect(self, item: Item, prevent_sweep: bool = False, location: Optional[Lo

return changed

def add_item(self, item: str, player: int, count: int = 1) -> None:
"""
Adds the item to state.

:param item: The item to be added.
:param player: The player the item is for.
:param count: How many of the item to add.
"""
assert count > 0
self.prog_items[player][item] += count

def remove(self, item: Item):
changed = self.multiworld.worlds[item.player].remove(self, item)
if changed:
Expand All @@ -1007,6 +1037,33 @@ def remove(self, item: Item):
self.blocked_connections[item.player] = set()
self.stale[item.player] = True

def remove_item(self, item: str, player: int, count: int = 1) -> None:
"""
Removes the item from state.

:param item: The item to be removed.
:param player: The player the item is for.
:param count: How many of the item to remove.
"""
assert count > 0
self.prog_items[player][item] -= count
if self.prog_items[player][item] < 1:
del (self.prog_items[player][item])

def set_item(self, item: str, player: int, count: int) -> None:
"""
Sets the item in state equal to the provided count.

:param item: The item to modify.
:param player: The player the item is for.
:param count: How many of the item to now have.
"""
assert count >= 0
if count == 0:
del (self.prog_items[player][item])
else:
self.prog_items[player][item] = count


class EntranceType(IntEnum):
ONE_WAY = 1
Expand Down Expand Up @@ -1280,8 +1337,8 @@ def add_exits(self, exits: Union[Iterable[str], Dict[str, Optional[str]]],
Connects current region to regions in exit dictionary. Passed region names must exist first.

:param exits: exits from the region. format is {"connecting_region": "exit_name"}. if a non dict is provided,
created entrances will be named "self.name -> connecting_region"
:param rules: rules for the exits from this region. format is {"connecting_region", rule}
created entrances will be named "self.name -> connecting_region"
:param rules: rules for the exits from this region. format is {"connecting_region": rule}
"""
if not isinstance(exits, Dict):
exits = dict.fromkeys(exits)
Expand Down Expand Up @@ -1550,21 +1607,19 @@ def create_playthrough(self, create_paths: bool = True) -> None:

# in the second phase, we cull each sphere such that the game is still beatable,
# reducing each range of influence to the bare minimum required inside it
restore_later: Dict[Location, Item] = {}
required_locations = {location for sphere in collection_spheres for location in sphere}
for num, sphere in reversed(tuple(enumerate(collection_spheres))):
to_delete: Set[Location] = set()
for location in sphere:
# we remove the item at location and check if game is still beatable
# we remove the location from required_locations to sweep from, and check if the game is still beatable
logging.debug('Checking if %s (Player %d) is required to beat the game.', location.item.name,
location.item.player)
old_item = location.item
location.item = None
if multiworld.can_beat_game(state_cache[num]):
required_locations.remove(location)
if multiworld.can_beat_game(state_cache[num], required_locations):
to_delete.add(location)
restore_later[location] = old_item
else:
# still required, got to keep it around
location.item = old_item
required_locations.add(location)

# cull entries in spheres for spoiler walkthrough at end
sphere -= to_delete
Expand All @@ -1581,7 +1636,7 @@ def create_playthrough(self, create_paths: bool = True) -> None:
logging.debug('Checking if %s (Player %d) is required to beat the game.', item.name, item.player)
precollected_items.remove(item)
multiworld.state.remove(item)
if not multiworld.can_beat_game():
if not multiworld.can_beat_game(multiworld.state, required_locations):
# Add the item back into `precollected_items` and collect it into `multiworld.state`.
multiworld.push_precollected(item)
else:
Expand Down Expand Up @@ -1623,9 +1678,6 @@ def create_playthrough(self, create_paths: bool = True) -> None:
self.create_paths(state, collection_spheres)

# repair the multiworld again
for location, item in restore_later.items():
location.item = item

for item in removed_precollected:
multiworld.push_precollected(item)

Expand Down
Loading
Loading