Compare commits

...

801 Commits

Author SHA1 Message Date
Holly 60c529edc9 Fix WebHost.py merge conflict 2025-02-01 21:31:59 +00:00
Jouramie 051518e72a
Stardew Valley: Fix unresolved reference warning and unused imports (#4360)
* fix unresolved reference warning and unused imports

* revert stuff

* just a commit to rerun the tests cuz messenger fail
2025-02-01 22:07:08 +01:00
Spineraks b7b78dead3
LADX: Fix generation error on minimal accessibility (#4281)
* [LADX] Fix minimal accessibility

* allow_partial for minimal accessibility

* create the correct partial_all_state

* skip our prefills rather than removing after

* dont rebuild our prefill list

---------

Co-authored-by: threeandthreee <a.l.nordstrom@gmail.com>
2025-02-01 22:03:49 +01:00
Jarno d1167027f4
Core: Make csv options output ignore hidden options (#4539)
* Core: Make csv options output ignore hidden options

* Update Options.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

---------

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
2025-02-01 02:26:59 +01:00
qwint 445c9b22d6
Settings: Handle empty Groups (#4576)
* export empty groups as an empty dict instead of crashing

* Update settings.py

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

* check instance values from self as well

* Apply suggestions from code review

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-02-01 02:11:04 +01:00
black-sliver 67e8877143
Docs: fix lower limit of valid IDs in network protocol.md (#4579) 2025-01-31 08:38:17 +01:00
agilbert1412 1fe8024b43
Stardew valley: Add Mod Recipes tests (#4580)
* `- Add Craftsanity Mod tests

* - Add the same test for cooking

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-01-30 09:19:06 +01:00
agilbert1412 8e14e463e4
Stardew Valley: Radioactive slot machine should be a ginger island check (#4578) 2025-01-30 09:05:51 +01:00
Jouramie b8666b2562
Stardew Valley: Remove weird magic trap test? (#4570) 2025-01-29 13:56:50 -05:00
Felix R 57afdfda6f
meritous: move completion_condition to set_rules (#4567) 2025-01-29 02:03:37 +01:00
black-sliver 738c21c625
Tests: massively improve the memory leak test performance (#4568)
* Tests: massively improve the memory leak test performance

With the growing number of worlds, GC becomes the bottleneck and slows down the test.

* Tests: fix typing in general/test_memory
2025-01-29 01:52:01 +01:00
black-sliver 41898ed640
MultiServer: implement NoText and deprecate uncompressed Websocket connections (#4540)
* MultiServer: add NoText tag and handling

* MultiServer: deprecate and warn for uncompressed connections

* MultiServer: fix missing space in no compression warning
2025-01-29 01:42:46 +01:00
agilbert1412 1ebc9e2ec0
Stardew Valley: Tests: Restructure the tests that validate Mods + ER together, improved performance (#4557)
* - Unrolled and improved the structure of the test for Mods + ER, to improve total performance and performance on individual tests for threading purposes

* Use | instead of Union[]

Co-authored-by: Jouramie <16137441+Jouramie@users.noreply.github.com>

* - Remove unused using

---------

Co-authored-by: Jouramie <16137441+Jouramie@users.noreply.github.com>
2025-01-28 23:19:20 +01:00
Silvris 9466d5274e
MM2: fix plando and weakness special cases (#4561) 2025-01-28 21:45:28 +01:00
NewSoupVi a53bcb4697
KH2: Use int(..., 0) in Client #4562 2025-01-27 23:13:10 +01:00
Exempt-Medic 8c5592e406
KH2: Fix determinism by using tuples instead of sets (#4548) 2025-01-27 11:06:10 -05:00
Bryce Wilson 41055cd963
Pokemon Emerald: Update changelog (#4551) 2025-01-27 17:01:18 +01:00
Scipio Wright 43874b1d28
Noita: Add clarification to check option descriptions (#4553) 2025-01-27 10:27:43 -05:00
Bryce Wilson b570aa2ec6
Pokemon Emerald: Clean up free fly blacklist (#4552) 2025-01-27 10:25:31 -05:00
Bryce Wilson c43233120a
Pokemon Emerald: Clarify death link and start inventory descriptions (#4517) 2025-01-27 10:24:26 -05:00
Silvris 57a571cc11
KDL3: Fix world access on non-strict open world (#4543)
* Update rules.py

* lambda capture
2025-01-27 01:52:02 +01:00
Fabian Dill 8622cb6204
Factorio: Inventory Spill Traps (#4457) 2025-01-26 22:14:39 +01:00
qwint 90417e0022
CommonClient: Expand on make_gui docstring (#4449)
* adds docstring to make_gui describing what things you might want to change without dealing with kivy/kvui directly (there are better places to document those)

* Update CommonClient.py

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

* Update CommonClient.py

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2025-01-26 13:06:27 +01:00
josephwhite 96b941ed35
Super Mario 64: Add Star Costs to Spoiler (#4544) 2025-01-25 09:36:23 -05:00
Bryce Wilson 1832bac1a3
BizHawkClient: Update README for `get_memory_size` (#4511) 2025-01-25 09:35:42 -05:00
qwint 86641223c1
Shivers: Stop using get_all_state cache to fix timing issue #4522
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-01-25 00:35:54 +01:00
black-sliver cc770418f2
MultiServer: optimize PrintJSON for !release (#4545)
* MultiServer: optimize PrintJSON for !release

* MultiServer: safer comparison

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2025-01-24 23:22:33 +01:00
Scipio Wright 513e361764
TUNIC: Fix UT create_item classification (#4514)
Co-authored-by: Silent <110704408+silent-destroyer@users.noreply.github.com>
2025-01-24 17:10:58 -05:00
Silent ddf7fdccc7
TUNIC: Add Torch Item (#4538)
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-01-24 16:57:23 -05:00
Silent 3df2dbe051
TUNIC: Add ability shuffle information to spoiler log (#4498) 2025-01-24 16:55:49 -05:00
Jasper den Brok 3d1d6908c8
Pokemon Emerald: Add Free Fly Blacklist (#4165)
Co-authored-by: Jasper den Brok <jasper.den.brok@gmail.com>
2025-01-24 16:30:21 -05:00
qwint 7474c27372
Core: Add launch function to call launch_subprocess only if multiprocessing is actually necessary (#4237)
* skips opening a subprocess if kivy (and thus the launcher gui) hasn't been loaded so stdin can function as expected on --nogui and similar

* this exists lol

* keep old function around and use new function for CC component

* fix name=None typing
2025-01-24 19:52:12 +01:00
Scipio Wright bb0948154d
TUNIC: Make the standard entrances get made with tuples instead of sets (#4546)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-01-24 12:42:31 -05:00
CookieCat fa2816822b
AHIT: Fix broken link in setup guide (#4524)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-01-23 16:45:11 -05:00
NewSoupVi 5a42c70675
Core: Fix worlds that rely on other worlds having their Entrances connected before connect_entrances, add unit test (#4530)
* unit test that get all state is called with partial entrances before connect_entrances

* fix the two worlds doing it

* lol

* unused import

* Update test/general/test_entrances.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update test_entrances.py

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-01-22 14:00:47 +01:00
JaredWeakStrike 949527f9cb
KH2: Bug fixes and game update future proofing (#4075)
Co-authored-by: qwint <qwint.42@gmail.com>
2025-01-21 17:28:33 -05:00
Scipio Wright 1a1b7e9cf4
TUNIC: Reduce range end for local_fill option #4534 2025-01-21 18:39:08 +01:00
Fabian Dill edacb17171
Factorio: remove debug print (#4533) 2025-01-21 16:12:53 +01:00
qwint 33fd9de281
Core: Add Retry to Priority Fill (#4477)
* adds a retry to priority fill in case the one item per player optimization would cause the priority fill to fail to find valid placements

* Update Fill.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-01-21 00:56:20 +01:00
qwint a126dee068
HK: some stuff ruff and pycodestyle complained about (#4523) 2025-01-20 23:42:12 +01:00
qwint e2b942139a
HK: Save GrubHuntGoal by value (#4521) 2025-01-20 19:10:29 +01:00
Scipio Wright 823b17c386
TUNIC: Make grass go in the regular location name group too (#4504)
* Make grass go in the normal loc group too

* Make it not overwrite old groups
2025-01-20 17:44:39 +01:00
Chris J. 05d1b2129a
Docs: Update ID Overlapping Docs (#4447) 2025-01-20 11:18:09 -05:00
NewSoupVi 436c0a4104
Core: Add connect_entrances world step/stage (#4420)
* Add connect_entrances

* update ER docs

* fix that test, but also ew

* Add a test that asserts the new finalization

* Rewrite test a bit

* rewrite some more

* blank line

* rewrite rewrite rewrite

* rewrite rewrite rewrite

* RE. WRITE.

* oops

* Bruh

* I guess, while we're at it

* giga oops

* It's been a long day

* Switch KH1 over to this design with permission of GICU

* Revert

* Oops

* Bc I like it

* Update locations.py
2025-01-20 16:07:15 +01:00
Scipio Wright 96f469c737
TUNIC: Fix hero relics not being prog if hex quest is on in combat logic #4509 2025-01-20 16:04:39 +01:00
Scipio Wright 4f77abac4f
TUNIC: Fix failure in 1-player grass (#4520)
* Fix failure in 1-player grass

* Update worlds/tunic/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-01-20 15:53:30 +01:00
massimilianodelliubaldini d5cd95c7fb
Docs: Clarify usage of slot data for trackers in World API doc (#3986)
* Clarify usage of slot data for trackers in world API.

* Typo.

* Update docs/world api.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update docs/world api.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update docs/world api.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update docs/world api.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Keep to 120 char lines.

---------

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-01-20 09:01:45 +01:00
Exempt-Medic a2fbf856ff
SMZ3: Change locality options earlier (#4424) 2025-01-19 23:07:01 -05:00
Exempt-Medic 4fa8c43266
FFMQ: Fix collect_item (#4433)
* Fix FFMQ collect_item
2025-01-19 23:06:09 -05:00
qwint 992841a951
CommonClient: abstract url handling so it's importable (#4068)
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: Jouramie <16137441+Jouramie@users.noreply.github.com>
2025-01-20 02:18:36 +01:00
Exempt-Medic eb3c3d6bf2
FFMQ: Adds Items Accessibility (#4322) 2025-01-19 20:12:44 -05:00
Fabian Dill 39847c5502
WebHost: sort slots by player_id in api blueprint (#4354) 2025-01-20 02:05:07 +01:00
NewSoupVi 130232b457
Core: Make log time an optional arg & setting for Generate.py as well #4312 2025-01-20 01:56:37 +01:00
Doug Hoskisson ca8ffe583d
Zillion: Priority Dead Ends Feature (#4220) 2025-01-19 18:31:09 -05:00
Doug Hoskisson 563794ab83
Zillion: Use Useful Item Classification (#4179) 2025-01-19 18:29:13 -05:00
Mysteryem 9443861849
Zillion: Finalize item locations in either generate_output or fill_slot_data (#4121)
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2025-01-19 18:20:45 -05:00
Nicholas Saylor cbf4bbbca8
OoT Adjuster: Remove per_slot_randoms (#4264) 2025-01-19 18:17:31 -05:00
Silvris 9e353ebb8e
SMZ3: Fix Itemlinks with link_replacement #4099 2025-01-19 07:17:12 -05:00
Bryce Wilson 9183e8f9c9
BizHawkClient: Use built-ins for typing (#4508) 2025-01-19 10:23:06 +01:00
Bryce Wilson 0bb657d2c8
Pokemon Emerald: Use new check_locations helper (#4518) 2025-01-19 10:21:54 +01:00
Jouramie 992f192529
Stardew Valley: Improve generation performance by around 11% by moving calculating from rule evaluation to collect (#4231) 2025-01-18 20:36:01 -05:00
Fabian Dill 1c9409cac9
CommonClient: implement check_locations to send missing locations only (#4484)
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-01-19 00:26:42 +01:00
NewSoupVi 005a143e3e
MultiServer: Add slot to SetReply packets (#3747)
* Add slot to datastorage set response

* update docs as well
2025-01-18 19:59:26 +01:00
CarlosBor 8732974857
ALttP: update Spanish Setup Docs (#2670)
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
2025-01-17 21:38:59 -05:00
black-sliver 1ac8349bd4
CI: update pyright (#4506) 2025-01-17 21:30:18 +01:00
qwint 2b9fa89050
Bizhawk: adds typing to bizhawk component launch (#4505) 2025-01-17 21:22:36 +01:00
Doug Hoskisson 23ea3c0efc
Core: some low-hanging fruit on the strict type check (#3416)
* Core: some low-hanging fruit on the strict type check

* bump pyright version

* bump pyright version

* bump pyright and remove file that's no longer easy
2025-01-17 20:14:21 +01:00
Pierre-Alain BESSERO 698d27aada
OoT: Allow Crowd Control support for Ocarina of Time (Bizhawk) #4501
Changed the name of the default "receive" function in order to work with Crowd Control
2025-01-17 20:06:20 +01:00
Ishigh1 3a46c9fd3e
LADX: Closing the client window closes the window (#4350) 2025-01-17 20:05:02 +01:00
black-sliver 9507300939
SoE: update to v050 (#4497)
* Cuts some cutscenes
* Adds meta data for tracker to detect settings
2025-01-17 18:53:29 +01:00
Scipio Wright 0d6db291de
TUNIC: Reorder options (#4491)
* Reorder options

* Also make ability shuffling on by default
2025-01-17 18:30:00 +01:00
digiholic d218dec826
MMBN3: Logic and Bug Fixes, New Checks (#3646)
* PMDs now check to make sure you have enough unlockers for all of them before any are in logic, to avoid softlocks

* Adds Humor and BlckMnd to the pool and sets logic for Villain and Comedian. Patch not yet updated to remove starting inventory

* Adds Serenade as a check

* Fixes hide and seek completion to use proper Yoka Zoo map. Updates bsdiff patch to 1.2

* Adds option for excluding Secret Area, and item/location groups for further customization

* Update worlds/mmbn3/Locations.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mmbn3/Regions.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mmbn3/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mmbn3/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mmbn3/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Replaces can_reach generic with can_reach_region or can_reach_location, where applciable

* Unlocker is now a progression item, Excluded Locations is now a Set

* Missed a merge marker

* Excluded locations is no longer a set since you can't append to a set with +=

* Excluded locations is now a set again since you apparent can append to a set with |=

* Replaces more lists with sets. Fixes wording in option descriptions

* Update worlds/mmbn3/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-01-17 08:41:12 -05:00
Aaron Wagener 3d5c277c31
Core: don't log warnings for plando_items and missing lttp options (#3606)
* Core: don't log a warning for the "options" that are valid in a game section but not on the options system

* don't rebuild a set every loop
2025-01-17 08:39:41 -05:00
Mysteryem a9435dc6bb
KH2: Reduce unnecessary packets sent/requested by the client (#4035) 2025-01-16 22:00:29 -05:00
Mysteryem 8f307c226b
Core: Fix the distribution of Options.Range.triangular() (#4283) 2025-01-16 21:59:38 -05:00
threeandthreee 4b8f990960
LADX: Swap out invalid characters in item names (#4495) 2025-01-16 21:59:19 -05:00
threeandthreee 3a5a4b89ee
LADX: improved warps across unexplored tiles (#4111) 2025-01-16 21:58:49 -05:00
JaredWeakStrike 1485882642
KH2: Fixes abilities overflowing into items and crashing the game (#4384)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-01-16 21:57:41 -05:00
Scipio Wright 2e4f5a64b3
TUNIC: Make the local_fill option load in a specific number of locations (#4488)
* Make it load in a specific number of locations

* TunicLocation -> Location

* Actually shuffle the list
2025-01-17 03:13:37 +01:00
Mysteryem 90f80ce1c1
AHiT: Various logic fixes (#4492)
* Fix Director boss photo logic

The rules were being added to for the "Director" boss in
`set_enemy_rules()`, which didn't exist because the boss created was
called "Conductor" instead.

The name of the boss has been changed to "Director", to match, because
it is more accurate due to DJ Grooves possibly being the boss instead of
The Conductor.

The missing logic was the `Hookshot Badge` requirement, however, the
boss events are only used as part of the `Camera Tourist - All Clear`
location, which requires every boss event to be reachable, and the
Toxic Flower boss also has a `Hookshot Badge` requirement, so the
missing `Hookshot Badge` for the Director boss had no effect on logic.

The boss event locations are hidden from spoiler output, so to get a
spoiler showing the Director boss event accessed before having
`Hookshot Badge`, spoiler output had to be modified to also show the
hidden locations. Example sphere from playthrough that should not be
possible because it gets the `Hookshot Badge` and the `Conductor` event
(now renamed to `Director`) in the same sphere:

```
5: {
  Act Completion (Time Rift - Dead Bird Studio): Relic (Crayon Box)
  Conductor - Dead Bird Studio Basement: Conductor
  Dead Bird Studio (Rift) - Page: Behind Cardboard Planet: Time Piece
  Dead Bird Studio (Rift) - Page: Near Time Rift Gate: Hookshot Badge
  Picture Perfect - Hats Buy Building: Metro Ticket - Blue
  Snatcher - Your Contract has Expired: Snatcher
}
```

* Add missing Hookshot + Painting logic for Toilet boss picture

Includes the Hard logic of crossing the gap with a cherry bridge instead
of hookshot and the expert logic of being able to skip the boss firewall
with a cherry hover.

* Fix Alpine Skyline - Goat Outpost Horn region

`Alpine Skyline - Goat Outpost Horn` is accessible from The Illness has
Spread, but was being added to the region that is only accessible from
Alpine Free Roam. `Alpine Skyline - Goat Outpost Horn` has been moved to
the region that is accessible from both The Illness has Spread and
Alpine Free Roam.

* Add missing HitType.umbrella logic for Top of HQ Coin in Beat the Heat

Like Heating up Mafia Town, the cannon to the Mafia HQ area only opens
once all the faucets have been turned off by hitting them. This requires
the Umbrella when umbrella logic is enabled, but the Snatcher Coin on
top of Mafia HQ was missing this requirement when accessed from Beat the
Heat.

* Add missing Main Objective requirement for auto-completed Bonus Stamps

When a Main Objective is not excluded, but the bonuses are excluded, the
bonuses auto-complete once the Main Objective is completed. The
requirement to complete the Main Objective was missing, so the logic was
incorrectly awarding bonus stamps as soon as a Contract was unlocked,
even when it was not possible to complete the Main Objective of that
Contract.

* Add missing Hookshot requirement for The Arctic Cruise - Toilet from Bon Voyage!

`The Arctic Cruise - Toilet` is accessed from the `Cruise Ship` region,
but it is only present in the Ship Shape and Bon Voyage! acts.

Ship Shape and Rock the Boat can access `Cruise Ship` without any items,
but Bon Voyage! requires the Hookshot Badge to reach `Cruise Ship`.

With how the logic was set up, it was incorrectly giving access to
`The Arctic Cruise - Toilet` if the player had access to Bon Voyage!
but only had access to `Cruise Ship` through Rock the Boat.

* Fix Expert logic Rush Hour-only ticket skips

The code was checking `if not world.options.NoTicketSkips:`, but that
would only be `True` for `False`. For "rush_hour" (for Rush Hour-only
ticket skips), it would be `False`, causing Rush Hour-only ticket skips
to act as if ticket skips were disabled.

* Remove Mystifying Time Mesa: Zipline gaining Hookshot requirement in moderate logic

Alpine Skyline - Mystifying Time Mesa: Zipline does not normally
require Hookshot Badge because it is an implied requirement due to only
being accessible from Alpine Free Roam which does require Hookshot
Badge. In normal logic difficulty, the location does not have an
explicit Hookshot Badge requirement, but moderate logic was adding a
Hookshot Badge requirement. This extraneous Hookshot Badge requirement
has been removed.

* Fix Act Completion (Queen Vanessa's Manor) not being accessible with Dweller Mask/Brewing Hat

It was logically requiring the Umbrella hit type only, whereas all the
other locations in Queen Vanessa's Manor require the Dweller Bell hit
type which additionally allows Dweller Mask or Brewing Hat.

* Remove Dweller Mask requirement for Subcon Forest - Tall Tree Hookshot Swing

The Dweller Mask is not used in the intended vanilla route to get this
item, so this requirement seems to have been a mistake.

* Remove unused SDJ option for Subcon Forest - Long Tree Climb Chest

Hard logic can already reach this location with nothing (other than
paintings), so the "or" logic of being able to perform an SDJ was
unused.

* Require any non-HUMT Mafia Town act for Hot Air Balloon with nothing

Two buckets/beach balls are required to bucket/ball hover, but there is
only a single beach ball accessible in Heating Up Mafia Town, and
no accessible buckets.

There is an alternative strategy for Top of Lighthouse that only
requires a single beach ball, so that location can still be reached with
nothing from Heating Up Mafia Town.

* Use `get_difficulty()` helper in `set_enemy_rules`

Co-authored-by: Exempt-Medic <60412657+exempt-medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+exempt-medic@users.noreply.github.com>
2025-01-17 03:10:41 +01:00
black-sliver 78904151b0
Test: fix typo in pytest.ini (#4502)
The typo disabled a bunch of tests :S
2025-01-17 02:10:48 +01:00
black-sliver 9d4bd6eebd
pytest: only check tests/ and worlds/ (#4500)
This allows having failing tests in CI in worlds_disabled
and allows moving worlds there to disable tests.
2025-01-17 01:53:50 +01:00
black-sliver 5c56dc0357
SoE: fix logic for drain cave with OoB (#4496)
Also adds py3.13 compat and missing hash for sdist
2025-01-17 01:27:36 +01:00
NewSoupVi c7810823e8
Core: Fix crash when trying to log an exception (#4313)
* Fix crash when trying to log an exception

In https://github.com/ArchipelagoMW/Archipelago/pull/3028, we added a new logging filter which checked `record.msg`. 

However, you can pass whatever you want into a logging call. In this case, what we missed was ecc3094c70/MultiServer.py (L530C1-L530C37), where we pass an Exception object as the message. This currently causes a crash with the new filter.

The logging module supports this. It has no typing and can handle passing objects as messages just fine.

What you're supposed to use, as far as I understand it, is `record.getMessage()` instead of `record.msg`.

* Update Utils.py

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2025-01-16 18:35:07 +01:00
threeandthreee 902d03d447
LADX: Stabilize Item Pool Option (#3935)
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-01-15 21:42:19 -05:00
Scipio Wright b7621a0923
TLoZ: Fix typo in setup guide (#4486) 2025-01-16 00:52:12 +01:00
Silent b7baaed391
TUNIC: Grass Randomizer (#3913)
* Fix certain items not being added to slot data

* Change where items get added to slot data

* Add initial grass randomizer stuff

* Fix rules

* Update grass.py

Improve location names

* Remove wand and gun from logic

* Update __init__.py

* Fix logic for two pieces of grass in atoll

* Make early bushes only contain grass

* Backport changes to grass rando (#20)

* Backport changes to grass rando

* add_rule instead of set_rule for the special cases, add special cases for back of swamp laurels area cause I should've made a new region for the swamp upper entrance

* Remove item name group for grass

* Update grass rando option descriptions

- Also ignore grass fill for single player games

* Ignore grass fill option for solo rando

* Update er_rules.py

* Fix pre fill issue

* Remove duplicate option

* Add excluded grass locations back

* Hide grass fill option from simple ui options page

* Check for start with sword before setting grass rules

* Update worlds/tunic/options.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Exclude grass from get_filler_item_name

- non-grass rando games were accidentally seeing grass items get shuffled in as filler, which is funny but probably shouldn't happen

* Update worlds/tunic/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Apply suggestions from code review

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* change the rest of grass_fill to local_fill

* Filter out grass from filler_items

* remove -> discard

* Update worlds/tunic/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* change has_stick to has_melee

* Update grass list with combat logic regions

* More fixes from combat logic merge

* Fix some dumb stuff (#21)

* Reorganize pre fill for grass

* Update option value passthrough

* Update __init__.py

* Fix region name

* Make separate pools for the grass and non-grass fills (#22)

* Make separate pools for the grass and non-grass fills

* Update worlds/tunic/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Fix those things in the PR (#23)

* Use excludable property

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-01-16 00:17:07 +01:00
Fabian Dill 9dac7d9cc3
MultiServer: update InvalidPacket text for location scouts (#4485) 2025-01-15 21:50:20 +01:00
Star Rauchenberger 1eefe23f11
Lingo: Add speed boost mode (#3989)
* Add speed boost mode

* Update generated.dat

* Modify the actual trap weights option when speed boost mode is on

* EOF newline

* Update generated.dat
2025-01-15 21:13:29 +01:00
Exempt-Medic 207a76d1b5
OoT: Two Bugfixes (#4389) 2025-01-14 16:39:13 -05:00
Fabian Dill 01df35f215
Factorio: fix Evolution Trap crashing bound server (#4366) 2025-01-14 22:24:46 +01:00
NewSoupVi bedf746f1d
MultiServer: Revert hints being created for already found locations #4367 2025-01-14 21:37:10 +01:00
Exempt-Medic b91a7ac6fb
LADX: Move Locality Changes Earlier (#4478) 2025-01-14 13:52:58 -05:00
agilbert1412 79e6beeec3
Stardew Valley: Update Mod Content (#4416) 2025-01-14 12:47:12 -05:00
Exempt-Medic dae9d4c575
LTTP: Fix Itemlinks (#4479) 2025-01-14 12:34:40 -05:00
Nicholas Saylor 04928bd83d
DKC3: Remove unused variables and imports #4302 2025-01-14 10:49:30 +01:00
Scipio Wright 0f3818e711
Utils: Visualize Regions showing the reachable regions in color (#4436)
* Utils with coloring

* Update example use

* Update Utils.py

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2025-01-14 10:45:59 +01:00
threeandthreee 0f1dc6e19c
Codeowners: @threeandthreee as LADX maintainer #4216 2025-01-14 01:35:29 +01:00
Exempt-Medic ffd0c8b341
Blasphemous: Move Locality Changes Earlier (#4422) 2025-01-13 19:34:56 -05:00
Exempt-Medic 6220963195
Tests: No Creating Items/Locations/Regions in __init__ (#4474) 2025-01-13 18:35:44 -05:00
Exempt-Medic 20119e3162
Faxanadu: Fix generations with itemlinks (#4395) 2025-01-13 18:35:01 -05:00
Louis M 4cb8fa3cdd
Aquaria: Fixing itemlink not working (#4473) 2025-01-13 20:09:39 +01:00
qwint 93e8613da7
HK: Abstract and default grub counts (#4336) 2025-01-13 11:08:46 -05:00
Aaron Wagener f9cc19e150
Fill: Crash if there are remaining unfilled locations (#2830) 2025-01-13 10:52:10 -05:00
Sam Merritt 0f1c119c76
Factorio: improve error message for config validation (#4421) 2025-01-13 09:52:21 +01:00
Alchav 4c734b467f
LTTP: Shop and Arrow fixes (#4067)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-01-13 08:32:59 +01:00
Silvris 1f966ee705
BizhawkClient: set metadata from patch file (#4346) 2025-01-12 19:01:16 +01:00
Nicholas Saylor 172ad4e57d
Adventure: Optimize imports (#4300) 2025-01-12 19:00:20 +01:00
Justus Lind 3f935aac13
Muse Dash: Change Data storage from a .txt file to a .py file and Filter Webhost Song Lists correctly (#4234) 2025-01-12 18:59:16 +01:00
qwint 9928639ce2
Docs: Fix Typo in Rich Text Options Flag Documentation (#4462) 2025-01-12 11:01:42 -05:00
Jouramie 0fc722cb28
Stardew Valley: Remove seasonal farming event, use regions instead (#4379) 2025-01-12 11:01:02 -05:00
Bryce Wilson 4edca0ce54
BizHawkClient: Add command to get size of memory domain (#4439)
* Mega Man 2: Remove mm2 commands from client if rom size too small
2025-01-12 08:03:31 +01:00
Bryce Wilson 70942eda8c
BizHawkClient: Fix version warning not falling through to regular execution (#4463) 2025-01-12 07:54:48 +01:00
NewSoupVi adcb2f59ca
MultiServer: Correct tying of Context.groups (#4460) 2025-01-11 22:16:01 +01:00
Alchav 29b34ca9fd
Pokémon R/B: Fix Route 11-E to Route-12-W logic (#4435) 2025-01-11 01:31:29 +01:00
Fabian Dill d97ee5d209
Core: update certifi (#4453) 2025-01-10 23:28:57 +01:00
Fabian Dill c2bd9df0f7
Subnautica: fix typo and remove no longer used logger (#4456) 2025-01-10 23:28:38 +01:00
Scipio Wright 112bfe0933
TUNIC: Logic for Beneath the Vault Bridge Switch #4432 2025-01-10 22:48:15 +01:00
Alchav 96b500679d
LTTP: Add missing GT Pre-Moldorm Bomb Wall Logic (#4440) 2025-01-10 22:40:50 +01:00
Scipio Wright 258ea10c52
TUNIC: Modify UT support to make a better pattern (#3860)
* Modify UT support to make a better pattern

* Handle keyerror for logic_rules option

* Missed self.passthrough value setting

* Less laziness for passthrough

* Remove extra newline

* Fix missing using_ut = True, also remove now unnecessary try except since 0.5.1 is out

* New UT thing, it goes in this PR because it's been open for 5 months for a very very tiny change
2025-01-10 21:49:13 +01:00
lordlou 043ba418ec
SM generate without rom (#3460)
* - SM now displays message when getting an item outside for someone else (fills ROM item table)

This is dependant on modifications done to sm_randomizer_rom project

* First working MultiWorld SM

* some missing things:

- player name inject in ROM and get in client
- end game get from ROM in client
- send self item to server
- add player names table in ROM

* replaced CollectionState inheritance from SMBoolManager with a composition of an array of it (required to generation more than one SM world, which is still fails but is better)

* - reenabled balancing

* post rebase fixes

* updated SmClient.py

* + added VariaRandomizer LICENSE

* + added sm_randomizer_rom project (which builds sm.ips)

* Moved VariaRandomizer and sm_randomizer_rom projects inside worlds/sm and done some cleaning

* properly revert change made to CollectionState and more cleaning

* Fixed multiworld support patch not working with VariaRandomizer's

* missing file commit

* Fixed syntax error in unused code to satisfy Linter

* Revert "Fixed multiworld support patch not working with VariaRandomizer's"

This reverts commit fb3ca18528bb331995e3d3051648c8f84d04c08b.

* many fixes and improovement

- fixed seeded generation
- fixed broken logic when more than one SM world
- added missing rules for inter-area transitions
- added basic patch presence for logic
- added DoorManager init call to reflect present patches for logic
- moved CollectionState addition out of BaseClasses into SM world
- added condition to apply progitempool presorting only if SM world is present
- set Bosses item id to None to prevent them going into multidata
- now use get_game_players

* first working (most of the time) progression generation for SM using VariaRandomizer's rules, items, locations and accessPoint (as regions)

* first working single-world randomized SM rom patches

* - SM now displays message when getting an item outside for someone else (fills ROM item table)

This is dependant on modifications done to sm_randomizer_rom project

* First working MultiWorld SM

* some missing things:

- player name inject in ROM and get in client
- end game get from ROM in client
- send self item to server
- add player names table in ROM

* replaced CollectionState inheritance from SMBoolManager with a composition of an array of it (required to generation more than one SM world, which is still fails but is better)

* - reenabled balancing

* post rebase fixes

* updated SmClient.py

* + added VariaRandomizer LICENSE

* + added sm_randomizer_rom project (which builds sm.ips)

* Moved VariaRandomizer and sm_randomizer_rom projects inside worlds/sm and done some cleaning

* properly revert change made to CollectionState and more cleaning

* Fixed multiworld support patch not working with VariaRandomizer's

* missing file commit

* Fixed syntax error in unused code to satisfy Linter

* Revert "Fixed multiworld support patch not working with VariaRandomizer's"

This reverts commit fb3ca18528bb331995e3d3051648c8f84d04c08b.

* many fixes and improovement

- fixed seeded generation
- fixed broken logic when more than one SM world
- added missing rules for inter-area transitions
- added basic patch presence for logic
- added DoorManager init call to reflect present patches for logic
- moved CollectionState addition out of BaseClasses into SM world
- added condition to apply progitempool presorting only if SM world is present
- set Bosses item id to None to prevent them going into multidata
- now use get_game_players

* Fixed multiworld support patch not working with VariaRandomizer's

Added stage_fill_hook to set morph first in progitempool
Added back VariaRandomizer's standard patches

* + added missing files from variaRandomizer project

* + added missing variaRandomizer files (custom sprites)

+ started integrating VariaRandomizer options (WIP)

* Some fixes for player and server name display

- fixed player name of 16 characters reading too far in SM client
- fixed 12 bytes SM player name limit (now 16)
- fixed server name not being displayed in SM when using server cheat ( now displays RECEIVED FROM ARCHIPELAGO)
- request: temporarly changed default seed names displayed in SM main menu to OWTCH

* Fixed Goal completion not triggering in smClient

* integrated VariaRandomizer's options into AP (WIP)

- startAP is working
- door rando is working
- skillset is working

* - fixed itemsounds.ips crash by always including nofanfare.ips into multiworld.ips (itemsounds is now always applied and "itemsounds" preset must always be "off")

* skillset are now instanced per player instead of being a singleton class

* RomPatches are now instanced per player instead of being a singleton class

* DoorManager is now instanced per player instead of being a singleton class

* - fixed the last bugs that prevented generation of >1 SM world

* fixed crash when no skillset preset is specified in randoPreset (default to "casual")

* maxDifficulty support and itemsounds removal

- added support for maxDifficulty
- removed itemsounds patch as its always applied from multiworld patch for now

* Fixed bad merge

* Post merge adaptation

* fixed player name length fix that got lost with the merge

* fixed generation with other game type than SM

* added default randoPreset json for SM in playerSettings.yaml

* fixed broken SM client following merge

* beautified json skillset presets

* Fixed ArchipelagoSmClient not building

* Fixed conflict between mutliworld patch and beam_doors_plms patch

- doorsColorsRando now working

* SM generation now outputs APBP

- Fixed paths for patches and presets when frozen

* added missing file and fixed multithreading issue

* temporarily set data_version = 0

* more work

- added support for AP starting items
- fixed client crash with gamemode being None
- patch.py "compatible_version" is now 3

* commited missing asm files

fixed start item reserve breaking game (was using bad write offset when patching)

* Nothing item are now handled game-side. the game will now skip displaying a message box for received Nothing item (but the client will still receive it).

fixed crash in SMClient when loosing connection to SNI

* fixed No Energy Item missing its ID

fixed Plando

* merge post fixes

* fixed start item Grapple, XRay and Reserve HUD, as well as graphic beams (except ice palette color)

* fixed freeze in blue brinstar caused by Varia's custom PLM not being filled with proper Multiworld PLM address (altLocsAddresses)

* fixed start item x-ray HUD display

* Fixed start items being sent by the server (is all handled in ROM)

Start items are now not removed from itempool anymore
Nothing Item is now local_items so no player will ever pickup Nothing. Doing so reduces contribution of this world to the Multiworld the more Nothing there is though.
Fixed crash (and possibly passing but broken) at generation where the static list of IPSPatches used by all SM worlds was being modified

* fixed settings that could be applied to any SM players

* fixed auth to server only using player name (now does as ALTTP to authenticate)

* - fixed End Credits broken text

* added non SM item name display

* added all supported SM options in playerSettings.yaml

* fixed locations needing a list of parent regions (now generate a region for each location with one-way exits to each (previously) parent region

did some cleaning (mainly reverts on unnecessary core classes

* minor setting fixes and tweaks

- merged Area and lightArea settings
- made missileQty, superQty and powerBombQty use value from 10 to 90 and divide value by float(10) when generating
- fixed inverted layoutPatch setting

* added option start_inventory_removes_from_pool

fixed option names formatting
fixed lint errors
small code and repo cleanup

* Hopefully fixed ROR2 that could not send any items

* - fixed missing required change to ROR2

* fixed 0 hp when respawning without having ever saved (start items were not updating the save checksum)

* fixed typo with doors_colors_rando

* fixed checksum

* added custom sprites for off-world items (progression or not)

the original AP sprite was made with PierRoulette's SM Item Sprite Utility by ijwu

* - added missing change following upstream merge

- changed patch filename extension from apbp to apm3 so patch can be used with the new client

* added morph placement options: early means local and sphere 1

* fixed failing unit tests

* - fixed broken custom_preset options

* - big cleanup to remove unnecessary or unsupported features

* - more cleanup

* - moved sm_randomizer_rom and all always applied patches into an external project that outputs basepatch.ips

- small cleanup

* - added comment to refer to project for generating basepatch.ips (https://github.com/lordlou/SMBasepatch)

* fixed g4_skip patch that can be not applied if hud is enabled

* - fixed off world sprite that can have broken graphics (restricted to use only first 2 palette)

* - updated basepatch to reflect g4_skip removal

- moved more asm files to SMBasepatch project

* - tourian grey doors at baby metroid are now always flashing (allowing to go back if needed)

* fixed wrong path if using built as exe

* - cleaned exposed maxDifficulty options

- removed always enabled Knows

* Merged LttPClient and SMClient into SNIClient

* added varia_custom Preset Option that fetch a preset (read from a new varia_custom_preset Option) from varia's web service

* small doc precision

* - added death_link support

- fixed broken Goal Completion
- post merge fix

* - removed now useless presets

* - fixed bad internal mapping with maxDiff

- increases maxDiff if only Bosses is preventing beating the game

* - added support for lowercase custom preset sections (knows, settings and controller)

- fixed controller settings not applying to ROM

* - fixed death loop when dying with Door rando, bomb or speed booster as starting items

- varia's backup save should now be usable (automatically enabled when doing door rando)

* -added docstring for generated yaml

* fixed bad merge

* fixed broken infinity max difficulty

* commented debug prints

* adjusted credits to mark progression speed and difficulty as Non Available

* added support for more than 255 players (will print Archipelago for higher player number)

* fixed missing cleanup

* added support for 65535 different player names in ROM

* fixed generations failing when only bosses are unreachable

* - replaced setting maxDiff to infinity with a bool only affecting boss logics if only bosses are left to finish

* fixed failling generations when using 'fun' settings

Accessibility checks are forced to 'items' if restricted locations are used by VARIA following usage of 'fun' settings

* fixed debug logger

* removed unsupported "suits_restriction" option

* fixed generations failing when only bosses are unreachable (using a less intrusive approach for AP)

* - fixed deathlink emptying reserves

- added death_link_survive option that lets player survive when receiving a deathlink if the have non-empty reserves

* - merged death_link and death_link_survive options

* fixed death_link

* added a fallback default starting location instead of failing generation if an invalid one was chosen

* added Nothing and NoEnergy as hint blacklist

added missing NoEnergy as local items and removed it from progression

* SM Varia can now generate without ROM

* removed stage_assert_generate
2025-01-10 21:46:17 +01:00
Fabian Dill 894a8571ee
kvui: add autocompleting new hint text input (#3535)
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>
2025-01-10 20:21:02 +01:00
ruby0b 874197d940
Linux: move the user home Archipelago dir to $XDG_DATA_HOME (#4347)
This affects builds with non-writable installation directories.
Instead of saving data in ~/Archipelago we now use $XDG_DATA_HOME/Archipelago
(defaulting to ~/.local/share/Archipelago).
If ~/Archipelago still exists we move it to the new location and link ~/Archipelago to it.

Motivation: This follows the [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/latest/)
to at least some degree and doesn't clutter the user's home directory.
2025-01-10 01:27:49 +01:00
agilbert1412 d3ed40cd4d
Stardew Valley: Hide the Mods from the simple options page (#4446) 2025-01-08 08:13:32 +01:00
Aaron Wagener a29ba4a6c4
The Messenger: reduce strictness of output path check (#4442) 2025-01-07 23:11:26 +01:00
Fabian Dill fe06fe075e
Factorio: add fluid mining technology to logic requirements (#4385) 2025-01-07 23:06:48 +01:00
qwint de58cb03da
Core: Pickle hints by value (#4441) 2025-01-07 22:24:19 +01:00
TheLX5 3204680662
SNIClient: Let clients based on SNIClient monitor packages via on_package method (#3093) 2025-01-07 00:10:23 +01:00
shananas 07e896508c
KH2: Doc Updates (#4434) 2025-01-06 14:02:04 -05:00
Scipio Wright 2d3faea713
Core: Include unfilled locations in error when there are not enough locations for progression items (#4285)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-01-06 09:52:33 -05:00
eudaimonistic 7c89a83d19
Docs: Clarify !alias commands in commands_en.md (#4426)
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
2025-01-06 09:42:18 -05:00
qwint 16f8b41cb9
Core: add docstrings for launcher components (#4148)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-01-06 09:35:37 -05:00
qwint 7d506990f5
HK: add location counts to option descriptions (#4083) 2025-01-06 09:35:12 -05:00
qwint aadcb4c903
HK: use rich_text_options_doc to make webhost formatting look better (#4079) 2025-01-06 09:21:44 -05:00
coveleski daf94fcdb2
Pokemon RB: Fixing misnamed locations (#4404) 2025-01-04 08:27:41 -05:00
Kory Dondzila 1cef659b78
Shivers: Fix spelling error in naming (#4425) 2025-01-04 07:42:34 -05:00
Scipio Wright 25381ef2c2
Core: Make the error for a missing option display the player name (#4430) 2025-01-04 07:29:30 -05:00
Mysteryem 5927926314
Blasphemous: Fix starting_location: random affecting all Blasphemous worlds (#4428)
Option resolution for the `StartingLocation` option (the only
`ChoiceIsRandom` subclass) was writing to the `randomized` attribute on
the class instead of on the instance, meaning that
`self.options.starting_location.randomized` would be `True` for all
Blasphemous players in the multiworld if any one of the players set
their `StartingLocation` option to `"random"`.

This patch fixes the issue by writing to the `randomized` attribute on
the new instance instead of on the class.
2025-01-03 07:03:30 -05:00
CaitSith2 2a11d9fec3
try again to award the starting items post cutscene if needed. (#4408) 2025-01-02 19:45:32 -08:00
Nicholas Saylor 82c44aaa22
FFMQ: Fix encoding issue with Game Page (#4299) 2025-01-02 22:03:07 -05:00
Kory Dondzila a7b483e4b7
Shivers: Adds ixupi captures priority option (#4403) 2025-01-02 10:12:00 -05:00
Fabian Dill 917335ec54
Core: it's 2025 (#4417) 2025-01-01 02:02:18 +01:00
Mysteryem 6e59ee2926
Zork Grand Inquisitor: Precollect Start with Hotspot Items in deterministic order (#4412) 2024-12-31 09:16:29 -05:00
Mysteryem 3c9270d802
FFMQ: Create itempool in deterministic order (#4413) 2024-12-31 09:02:02 -05:00
Mysteryem c4bbcf9890
TUNIC: Add relics and abilities to the item pool in deterministic order (#4411) 2024-12-30 23:57:09 -05:00
NewSoupVi 8dbecf3d57
The Witness: Make location order in the spoiler log deterministic (#3895)
* Fix location order

* Update worlds/witness/data/static_logic.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-12-30 00:50:39 +01:00
Fabian Dill 0de1369ec5
Factorio: hide hidden vanilla techs in factoriopedia too (#4332) 2024-12-29 11:56:41 -08:00
Fabian Dill fa95ae4b24
Factorio: require version that fixes a randomizer exploit (#4391) 2024-12-29 11:55:40 -08:00
CaitSith2 2065246186
Factorio: Make it possible to use rocket part in blueprint parameterization. (#4396)
This allows for example, making a blueprint of your rocket silo with requester chests specifying a request for the 2-8 rocket part ingredients needed to build the rocket.
2024-12-29 20:13:34 +01:00
Kory Dondzila ca1b3df45b
Shivers: Follow on PR to cleanup options #4401 2024-12-27 23:38:01 +01:00
Kory Dondzila 3bcc86f539
Shivers: Add events and fix require puzzle hints logic (#4018)
* Adds some events, renames things, fails for many players.

* Adds entrance rules for requires hints.

* Cleanup and add goal item.

* Cleanup.

* Add additional rule.

* Event and regions additions.

* Updates from merge.

* Adds collect behavior option.

* Fix missing generator location.

* Fix whitespace and optimize imports.

* Switch location order back.

* Add name replacement for storage.

* Fix test failure.

* Improve puzzle hints required.

* Add missing locations and cleanup indirect conditions.

* Fix naming.

* PR feedback.

* Missed comment.

* Cleanup imports, use strings for option equivalence, and update option description.

* Fix rule.

* Create rolling buffer goal items and remove goal items and location from default options.

* Cleanup.

* Removes dateutil.

* Fixes Subterranean World information plaque.
2024-12-27 21:07:55 +01:00
BadMagic100 218f28912e
Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER

* Move ERType to Entrance.Type, fix typing imports

* updates based on testing (read: flailing)

* Updates from feedback

* Various bug fixes in ERCollectionState

* Use deque instead of queue.Queue

* Allow partial entrances in collection state earlier, doc improvements

* Prevent early loops in region graph, improve reusability of ER stage code

* Typos, grammar, PEP8, and style "fixes"

* use RuntimeError instead of bare Exceptions

* return tuples from connect since it's slightly faster for our purposes

* move the shuffle to the beginning of find_pairing

* do er_state placements within pairing lookups to remove code duplication

* requested adjustments

* Add some temporary performance logging

* Use CollectionState to track available exits and placed regions

* Add a method to automatically disconnect entrances in a coupled-compliant way

 Update docs and cleanup todos

* Make find_placeable_exits deterministic by sorting blocked_connections set

* Move EntranceType out of Entrance

* Handle minimal accessibility, autodetect regions, and improvements to disconnect

* Add on_connect callback to react to succeeded entrance placements

* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure

* First set of unit tests for generic ER

* Change on_connect to send lists, add unit tests for EntranceLookup

* Fix duplicated location names in tests

* Update tests after merge

* Address review feedback, start docs with diagrams

* Fix rendering of hidden nodes in ER doc

* Move most docstring content into a docs article

* Clarify when randomize_entrances can be called safely

* Address review feedback

* Apply suggestions from code review

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection

* Documentation clarifications

* Update groups to allow any hashable

* Restrict groups from hashable to int

* Implement speculative sweeping in stage 1, address misc review comments

* Clean unused imports in BaseClasses.py

* Restrictive region/speculative sweep test

* sweep_for_events->advancement

* Remove redundant __str__

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

* Allow partial entrances in auto indirect condition sweep

* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends

* Typing fixes suggested by mypy

* Remove erroneous newline 

Not sure why the merge conflict editor is different and worse than the normal editor. Crazy

* Use modern typing for ER

* Enforce the use of explicit indirect conditions

* Improve doc on required indirect conditions

---------

Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2024-12-27 21:04:02 +01:00
Exempt-Medic b9642a482f
KH2: Using fast_fill instead of fill_restrictive (#4227) 2024-12-26 17:04:21 -05:00
Mysteryem 33ae68c756
DS3: Convert post_fill to stage_post_fill for better performance (#4122)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-12-26 08:50:18 -05:00
NewSoupVi 62942704bd
The Witness: Add info about which door items exist in the pool to slot data (#3583)
* This feature is just broken lol

* simplify

* mypy

* Expand the unit test for forbidden doors
2024-12-25 21:55:15 +01:00
NewSoupVi fe81053521
Core: Give the option to worlds to have a remaining fill that respects excluded locations (#3738)
* Give the option to worlds to have a remaining fill that respects excluded

* comment
2024-12-25 21:53:05 +01:00
NewSoupVi 222c8aa0ae
Core: Reword item classification definitions to allow for progression + useful (#3925)
* Core: Reword item classification definitions to allow for progression + useful

* Update network protocol.md

* Update world api.md

* Update Fill.py

* Docstrings

* Update BaseClasses.py

* Update advanced_settings_en.md

* Update advanced_settings_en.md

* Update advanced_settings_en.md

* space
2024-12-25 21:47:51 +01:00
NewSoupVi 845000d10f
Docs: Make an actual LogicMixin spec & explanation (#3975)
* Docs: Make an actual LogicMixin spec & explanation

* Update world api.md

* Update world api.md

* Update world api.md

* Update world api.md

* Update world api.md

* Update world api.md

* Update world api.md

* Update world api.md

* Update world api.md

* Update world api.md

* Update docs/world api.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update docs/world api.md

* Update world api.md

* Code corrections / actually follow own spec

* Update docs/world api.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update world api.md

* Update world api.md

* Reorganize / Rewrite the parts about optimisations a bit

* Update world api.md

* Write a big motivation paragraph

* Update world api.md

* Update world api.md

* line break issues

* Update docs/world api.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update docs/world api.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update docs/world api.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update world api.md

* Update docs/world api.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2024-12-25 21:47:17 +01:00
NewSoupVi b05f81b4b4
The Witness: Fix bridge/elevator items being progression when they shouldn't be #4392 2024-12-25 10:58:27 +01:00
Mysteryem 6c1dc5f645
Landstalker: Fix paths Lantern logic affecting other Landstalker worlds (#4394)
The data from `WORLD_PATHS_JSON` is supposed to be constant logic data
shared by all Landstalker worlds, but `add_path_requirements()` was
modifying this data such that after adding a `Lantern` requirement for a
dark region, subsequent Landstalker worlds to have their logic set could
also be affected by this `Lantern` requirement and previous Landstalker
worlds without damage boosting logic could also be affected by this
`Lantern` requirement because they could all be using the same list
instances. This issue would only occur for paths that have
`"requiredItems"` because all paths without required items would create
a new empty list, avoiding the problem.

The items in `data["itemsPlacedWhenCrossing"]` were also getting added
once for each Landstalker player, but there are no paths that have both
`"itemsPlacedWhenCrossing"` and `"requiredItems"`, so all such cases
would start from a new empty list of required items and avoid modifying
`WORLD_PATHS_JSON`.
2024-12-24 20:44:47 -05:00
Dinopony 5578ccd578
Landstalker: Fix issues on generation (#4345) 2024-12-24 14:08:03 -05:00
Mysteryem 78637c96a7
Tests: Add spheres test for missing indirect conditions (#3924)
Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-12-24 12:38:46 -05:00
Richard Snider f3ec82962e
Core: Add JSONMessagePart for Hint Status (Hint Priority) (#4387)
* add hint_status JSONMessagePart handling

* add docs for hint_status JSONMessagePart

* fix link ordering

* Rename hint_status type in docs

Co-authored-by: Emily <35015090+EmilyV99@users.noreply.github.com>

* Remove redundant explanation of hint_status field

Co-authored-by: Emily <35015090+EmilyV99@users.noreply.github.com>

* Fix formatting on hint status docs again

Co-authored-by: Emily <35015090+EmilyV99@users.noreply.github.com>

---------

Co-authored-by: Emily <35015090+EmilyV99@users.noreply.github.com>
2024-12-22 19:05:43 +01:00
DrBibop 4f590cdf7b
Inscryption: Implement new game (#3621)
* Worked locally before that so this is a lot of work . So, initial push

* Changes in init with better create_regions (Thanks to Phar on discord). Add a rule for victory. Change the regions list to remove menu in the destination.

* Added tests for location rules and changed rule locations to lists instead of sets

* Fixed game var in InscryptionLocation

* Fixed location access by using the same system from The Messenger

* Remove unuse rules in init and add region rules. Add all the act 2 locations and items.

* Add locations rule for the left of the bridge in act 2

* Added test for bridge requirement and added a dash to locationfor clarity

* Added more act 2 rules and removed completion rule

* Created docs for website, added Salmon Card item, marked multiple items as "progression", renamed tomb checks, added more location rules, re-added completion rule

* Renamed tower bath check to "Tentacle", added monocle as requirement for some checks, adjusted setup doc a bit

* Added tentacle to monocle test

* Added forest burrow chest rule

* Switch the two clock location because the id was swapped and screwed with the logic

* Added Ancient Obol rule and adjusted docs

* Added act 3 locations/items/rules/tests

* Added drone & battery to trader rules

* Fixed tutorial docs, added more act 3 rules, renamed holo pelt locations

* Add an option for the optional death card feature

* Added well check and quill item, added rules and tests

* Renamed Gems module and Gems drone

* Added slot data options

* Added rule for act 3 middle pelt

* Added option for randomize ability and uptade the randomize deck option to fit the new setup

* Added randomize ability in slot data

* Added more requirements for mycologists boss since it's pretty much an impossible fight early on

* Finished the french translation of the installation guide

* Changed the french title in the guide

* Added goal option and tests associated to it + fixed goal requirement missing quill

* Added goal option to docs and removed references to the now discarded API mod. Fixed some french translations.

* Added ourobot item + renamed some goal settings

* Fixed locations and items for act 1 goal

* Added skip tutorial option. Cleanup and rename of some options. Added tower requirement for Mycologist Key check. Fixed missing comma in act 2 locations oopsies.

* Added missing rules for Extra Battery, Nano Armor and Goobert's painting

* Added act 1 deathlink behaviour and epitaph pieces randomization options + made pieces progressive + adjusted docs

* Fixed some docs typos

* Added act 3 clock rule. Paintings 2, 3 and Goobert's painting can no longer contain progression items.

* New options system and fixed act 1 goal option breaking

* Added skip epilogue and painting checks balancing options. Renamed randomize abilities to randomize sigils. Fixed generation issue with epitaph pieces randomization. Goobert's painting no longer forces filler. Removed traps option for now. Reworded some option descriptions.

* Attempting type fix for python 3.8

* Attempting type fix for python 3.8 again

* Added starting only option for randomize deck

* Fixed arbitrary rule error

* Import fix attempt

* Migrated to DeathLinkMixin instead of creating a custom DeathLink option, cleaned up imports, renamed Death Link related options to include "death_link" instead of "deathlink", replaced numeral values for option checking into class attributes for readability, slight optimization to tower rule, fixed typo in codes option description.

* Added bug report page to web class, condensed pelt rules to one function, added items/locations count in game docs and adjusted some sections

* Added Inscryption to CODEOWNERS

* Implemented a bunch of suggestions: Better handling of painting option, options as dict for slot data, remove redundant auto_display_name, use of has_all, better goal tests, demote skink card to filler if goal is act 1 and force filler on paintings

* Makes clover plant and squirrel head progression items if paintings are balanced + fixed other issues

* filler items, start inventory from pool, '->"

* Fix bleeding issue

* Copy the list instead

* Fixed bleeding using proper deep copy

* Remove unnecessary for loops in tests

* Add defaults to choice options

---------

Co-authored-by: Benjamin Gregoire <benjamingregoire@outlook.com>
Co-authored-by: Exempt-Medic <ExemptMedic@Gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-12-21 23:12:35 +01:00
Kaito Sinclaire 46613adceb
SMZ3: Fix minimal logic considering SM boss tokens unnecessary (#4377) 2024-12-21 20:39:38 +01:00
threeandthreee e1a1cd1067
LADX: Open Mabe Option (#3964)
* open mabe option
swaps east mabe rocks for bushes

* add open mabe to slot data

* use upstream overworld option
Instead of a standalone option, use upstream's "overworld" option, which we don't use yet but it leaves better space for the future

* use ladxr_setting for consistency

* newline
2024-12-20 07:55:32 -05:00
Scipio Wright 7c8d102c17
TUNIC: Logic for bushes in guard house 2 upper and belltower (#4371)
* Logic for bushes in guard house 2 upper

* Fix typo

* also do it for forest belltower

* i love the dumb ice grapples
2024-12-19 23:45:29 -05:00
threeandthreee 35d30442f7
LADX: fix for syntax warning (#4376)
* init

* whitespace

* raw string instead
2024-12-19 22:53:58 -05:00
threeandthreee 4f71073d17
LADX: correct in-game check counter
LADX: correct in-game check counter
2024-12-19 22:17:41 -05:00
threeandthreee e142283e64
LADX: enable upstream options (#3962)
* enable some upstream settings

* flashing just disabled, no setting

* just enable fast text

* noflash and textmode as hidden options

* typo

* drop whitespace changes

* add hard mode to slot data

* textmode adjustments
fast text default (fixing mistake)
remove no text option (its buggy)

* unhide options

* Update worlds/ladx/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* adjustments
2024-12-19 21:19:00 -05:00
palex00 de3707af4a
Core/Docs: Adding apostrophe quotes around variables in printed error messages (#3914)
* Also indents plando_connections properly

* Adding apostrophe quotes around item, location, entrance/exit and boss names to make errors more readable

* Update plando_en.md

* Fixing test in Lufia II
2024-12-19 20:47:33 -05:00
Scipio Wright 2e0769c90e
Noita: Make greed die a trap (#4382)
Noita make greed die a trap
2024-12-19 20:30:41 -05:00
Louis M 1ded7b2fd4
Aquaria: Replacing the release link to the latest link (#4381)
* Replacing the release link to the latest link

* The fr link was not working
2024-12-19 20:17:56 -05:00
Bryce Wilson cacab68b77
Pokemon Emerald: Remove unnecessary code (#4364) 2024-12-16 09:06:48 +01:00
NewSoupVi 728d249202
Core: Add some more world convenience methods (#3021)
* Add some more convenience methods

* Typing stuff

* Rename the method

* beauxq's suggestions

* Back to Push Precollected
2024-12-15 23:30:35 +01:00
qwint d1823a21ea
HK: add random handling to plandocharmcosts (#4327) 2024-12-15 22:48:44 +01:00
Scipio Wright 6282efb13c
TUNIC: Additional Combat Logic Option (#3658) 2024-12-15 22:40:36 +01:00
Benjamin S Wolf 0fdc14bc42
Core: Deduplicate exception output (#4036)
When running Generate.py, uncaught exceptions are logged once to a file and twice to the console due to keeping the original excepthook. We can avoid this by filtering the file log out of the stream handler.
2024-12-15 22:29:56 +01:00
Mysteryem 0370e669e5
Pokemon Emerald: Add Mr Briney's House indirect conditions (#4154)
The `REGION_DEWFORD_TOWN/MAIN -> REGION_ROUTE109/BEACH` and
`REGION_ROUTE109/BEACH -> REGION_DEWFORD_TOWN/MAIN` entrances require
access to the
`REGION_ROUTE104_MR_BRINEYS_HOUSE/MAIN -> REGION_DEWFORD_TOWN/MAIN`
entrance in their access rules, so require indirect conditions for the
parent_region of the entrance: `REGION_ROUTE104_MR_BRINEYS_HOUSE/MAIN`.
2024-12-15 22:28:51 +01:00
threeandthreee ccea6bcf51
LADX: Improve icon guesses for foreign items (#2201)
* synonyms to new file, many added

* handle singular rupee

* remove redundant map and compass entries

* automatic pluralization

* add guardian acorn and piece of power

* move phrases to ItemIconGuessing.py

* organize, comment

* fix tab spacing

* fix

* add tunic and noita synonyms

* remove triangle instrument synonym

* reorganize, add some matches

* add tunic lucky up

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/ladx/ItemIconGuessing.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* handle camelCase and single rupee

* add indicate_progression option
Adds alternative system for foreign item icons that simply indicates whether or not the item is a progression item.

* improve splitting
drops some more characters, and also dont bother with rejoined stuff in name_cache because our splitting is better

* the witness stuff

* forbid more

* remove boost and surge

* Update worlds/ladx/ItemIconGuessing.py

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>

* match by game name
look at the name of the foreign game and only use game-specific entries for that game

* show message for all key drops

* updates from async test

* vi suggestions

* Adding FNAFW suggestions from @lolz1190 (#40)

* Adding FNAFW suggestions from @lolz1190

* missing comma

---------

Co-authored-by: threeandthreee <a.l.nordstrom@gmail.com>

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Co-authored-by: palex00 <32203971+palex00@users.noreply.github.com>
2024-12-13 22:49:30 +01:00
qwint 8d9454ea3b
Core: cast all the settings values so they don't try to get pickled later #4362 2024-12-12 21:36:56 +01:00
qwint 1ca8d3e4a8
Docs: add description of Indirect Condition problem (#4295)
* Docs: Dev FAQ - About indirect conditions

I wrote up a big effortpost about indirect conditions for nex on the [DS3 3.0 PR](https://github.com/ArchipelagoMW/Archipelago/pull/3128#discussion_r1693843193).

The version I'm [PRing to the world API document](https://github.com/ArchipelagoMW/Archipelago/pull/3552) is very brief and unnuanced, because I'd rather people use too many indirect conditions than too few.
But that might leave some devs wanting to know more.

I think that comment on nex's DS3 PR is probably the best detailed explanation for indirect conditions that exists currently.

So I think it's good if it exists somewhere. And the FAQ doc seems like the best place right now, because I don't want to write an entirely new doc at the moment.

* Actually copy in the text

* Update docs/apworld_dev_faq.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update docs/apworld_dev_faq.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update docs/apworld_dev_faq.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update docs/apworld_dev_faq.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update docs/apworld_dev_faq.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update docs/apworld_dev_faq.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update docs/apworld_dev_faq.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update docs/apworld_dev_faq.md

Co-authored-by: qwint <qwint.42@gmail.com>

* Update docs/apworld_dev_faq.md

Co-authored-by: qwint <qwint.42@gmail.com>

* Update apworld_dev_faq.md

* Update docs/apworld_dev_faq.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update apworld_dev_faq.md

* Update docs/apworld_dev_faq.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update docs/apworld_dev_faq.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update docs/apworld_dev_faq.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update apworld_dev_faq.md

* Update docs/apworld_dev_faq.md

Co-authored-by: qwint <qwint.42@gmail.com>

* Update docs/apworld_dev_faq.md

Co-authored-by: qwint <qwint.42@gmail.com>

* fix the last couple of wording issues I have with the indirect condition section to apworld dev faq doc

* I didn't like that wording

* Apply suggestions from code review

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Apply suggestions from code review

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update docs/apworld_dev_faq.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update docs/apworld_dev_faq.md

* Update docs/apworld_dev_faq.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2024-12-12 21:24:38 +01:00
qwint 9815306875
Docs: Use ModuleUpdate.py #3785 2024-12-12 20:30:49 +01:00
NewSoupVi d7736950cd
The Witness: Panel Hunt Plando (#3549)
* Add panel hunt plando option

* Keys are strs

* oops

* better message

* ,

* this doesn ot need to be here

* don't replace pre picked panels

* Update options.py

* rebase error

* rebase error

* oops

* Mypy

* ruff

* another rebase error

* actually this is a stupid change too

* bring over that change™️

* Update entity_hunt.py

* Update entity_hunt.py

* Update entity_hunt.py
2024-12-12 19:42:14 +01:00
Mysteryem f5e3677ef1
Pokemon Emerald: Fix invalid escape sequence warnings (#4328)
Generation on Python 3.12 would print SyntaxWarnings due to invalid '\d'
escape sequences added in #3832.

Use raw strings to avoid `\` being used to escape characters.
2024-12-12 19:04:27 +01:00
josephwhite 144d612c52
Super Mario 64: Rework logic for 100 Coins (#4131)
* sm64ex: Rework logic for 100 Coins

* sm64ex: 100 Coins Vanilla Option

* sm64ex: Avoiding raw int comparisons for 100 coin option

* sm64ex: Change 100 coin option from toggle to choice

* sm64ex: use snake_case for 100 coin option

* just use "vanilla" for option comparison (exempt-medic feedback)

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* sm64ex: remove vanilla 100 coins from item pool to remove overfilling stars

* yeah

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Remove range condition (35 is the min for total stars)

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-12-12 14:50:48 +01:00
LiquidCat64 3acbe9ece1
Castlevania: Circle of the Moon - Implement New Game (#3299)
* Add the cotm package with working seed playthrough generation.

* Add the proper event flag IDs for the Item codes.

* Oooops. Put the world completion condition in!

* Adjust the game name and abbreviations.

* Implement more settings.

* Account for too many start_inventory_from_pool cards with Halve DSS Cards Placed.

* Working (albeit very sloooooooooooow) ROM patching.

* Screw you, bsdiff! AP Procedure Patch for life!

* Nuke stage_assert_generate as the ROM is no longer needed for that.

* Working item writing and position adjusting.

* Fix the magic item graphics in Locations wherein they can be fixed.

* Enable sub-weapon shuffle

* Get the seed display working.

* Get the enemy item drop randomization working. Phew!

* Enemy drop rando and seed display fixes.

* Functional Countdown + Early Double setting

* Working multiworld (yay!)

* Fix item links and demo shenanigans.

* Add Wii U VC hash and a docs section explaining the rereleases.

* Change all client read/writes to EWRAM instead of Combined WRAM.

* Custom text insertion foundations.

* Working text converter and word wrap detector.

* More refinements to the text wrap system.

* Well and truly working sent/received messages.

* Add DeathLink and Battle Arena goal options.

* Add tracker stuff, unittests, all locations countdown, presets.

* Add to README, CODEOWNERS, and inno_setup

* Add to README, CODEOWNERS, and inno_setup

* Address some suggestions/problems.

* Switch the Items and Locations to using dataclasses.

* Add note about the alternate classes to the Game Page.

* Oooops, typo!

* Touch up the Options descriptions.

* Fix Battle Arena flag being detected incorrectly on connection and name the locked location/item pairs better.

* Implement option groups

* Swap the Lizard-man Locations into their correct Regions.

* Local start inventory, better DeathLink message handling, handle receiving over 255 of an item.

* Update the PopTracker pack links to no longer point to the Releases page.

* Add Skip Dialogues option.

* Update the presets for the accessibility rework.

* Swap the choices in the accessibility preset options.

* Uhhhhhhh...just see the apworld v4 changelog for this one.

* Ooops, typo!

* .

* Bunch of small stuff

* Correctly change "Fake" to "Breakable" in this comment.

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Make can_touch_water one line.

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Make broke_iron_maidens one line.

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Fix majors countdown and make can_open_ceremonial_door one line.

* Make the Trap AP Item less obvious.

* Add Progression + Useful stuff, patcher handling for incompatible versions, and fix some mypy stuff.

* Better option groups.

* Change Early Double to Early Escape Item.

* Update DeathLink description and ditch the Menu region.

* Fix the Start Broken choice for Iron Maiden Behavior

* Remove the forced option change with Arena goal + required All Bosses and Arena.

* Update the Game Page with the removal of the forced option combination change.

* Fix client potential to send packets nonstop.

* More review addressing.

* Fix the new select_drop code.

* Fix the new select_drop code for REAL this time.

* Send another LocationScout if we send Location checks without having the Location info.

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: Exempt-Medic <ExemptMedic@Gmail.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-12-12 14:47:47 +01:00
Scipio Wright 7d0b701a2d
TUNIC: Change rule for heir access in non-hex quest #4365 2024-12-12 12:54:03 +01:00
Justus Lind f91537fb48
Muse Dash: Remove bad option defaults. #4340 2024-12-12 09:18:19 +01:00
Jouramie 3c5ec49dbe
Stardew Valley: Fix potential incompletable seed when starting winter (#4361)
* make moss available with any season except winter

* add tool and region requirement for moss
2024-12-12 09:17:19 +01:00
NewSoupVi 9a37a136a1
The Witness: Add more panels to the "doors: panels" mode (#2916)
* Add more panels that should be panels

* Make it so the caves panel items don't exist in early caves

* Remove unused import

* oops

* Remove Jungle to Monastery Garden from usefulification list

* Add a basic test

* ruff

---------

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2024-12-10 21:13:45 +01:00
NewSoupVi 54a0a5ac00
The Witness: Put progression + useful on some items. (#4027)
* proguseful

* ruff

* variable rename

* variable rename

* Better (?) comment

* Better way to do this? I guess

* sure

* ruff

* Eh, it's not worth it. Here's the much simpler version

* don't need this now

* Improve some classification checks while we're at it

* Only proguseful obelisk keys if eps are individual
2024-12-10 21:06:06 +01:00
Exempt-Medic 704f14ffcd
Core: Add toggles_as_bools to options.as_dict (#3770)
* Add toggles_as_bools to options.as_dict

* Update Options.py

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

* Add param to docstring

* if -> elif

---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2024-12-10 20:37:54 +01:00
Star Rauchenberger 925fb967d3
Lingo: Fix number hunt issues on panels mode (#4342) 2024-12-10 20:36:38 +01:00
NewSoupVi 5dd19fccd0
MultiServer/CommonClient: We forgot about Item Links again (Hint Priority) (#4314)
* Vi don't forget about itemlinks challenge difficulty impossible

* People other than Vi also don't forget about ItemLinks challenge difficulty impossible
2024-12-10 20:35:36 +01:00
Jouramie 781100a571
CI: remove version restriction on pytest-subtests (#4356)
This reverts commit e3b5451672.
2024-12-10 20:26:33 +01:00
black-sliver 3fb0b57d19
Core: fix exceptions coming from LocationStore (#4358)
* Speedups: add instructions for ASAN

* Speedups: move typevars out of classes

* Speedups, NetUtils: raise correct exceptions

* Speedups: double-check malloc

* Tests: more LocationStore tests
2024-12-10 20:09:36 +01:00
Fabian Dill f79657b41a
WebHost: disable abbreviations for argparse (#4352) 2024-12-10 19:53:42 +01:00
black-sliver 4a5ba756b6
WebHost: Set Generator memory limit to 4GiB (#4319)
* WebHost: Set Generator memory limit to 4GiB

* WebHost: make generator memory limit configurable, better naming

* Update WebHostLib/__init__.py

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>

* Update docs/webhost configuration sample.yaml

---------

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2024-12-10 02:44:41 +01:00
black-sliver 0b3d34ab24
CI: update scan-build to v19 (#4338) 2024-12-10 02:25:09 +01:00
Jouramie aa22b62b41
Stardew Valley: Force deactivation of Mr. Qi's special orders when ginger island is deactivated (#4348) 2024-12-09 21:17:25 +01:00
Jouramie 51c4fe8f67
Stardew Valley: Fix a bug where walnutsanity would get deactivated even tho ginger island got forced activated (and move some files) (#4311) 2024-12-09 03:00:30 +01:00
Louis M 26f9720e69
Aquaria: mega refactoring (#3810)
This PR is mainly refactoring. Here is what changed:
- Changing item names so that each words are capitalized (`Energy Form` instead of `Energy form`)
- Removing duplication of string literal by using:
  - Constants for items and locations,
  - Region's name attribute for entrances,
- Clarify some documentations,
- Adding some region to be more representative of the game and to remove listing of locations in the rules (prioritize entrance rules over individual location rules).

This is the other minor modifications that are not refactoring:
- Adding an early bind song option since that can be used to exit starting area.
- Changing Sun God to Lumerean God to be coherent with the other gods.
- Changing Home Water to Home Waters and Open Water to Open Waters to be coherent with the game.
- Removing a rules to have an attack to go in Mithalas Cathedral since you can to get some checks in it without an attack.
- Adding some options to slot data to be used with Poptracker.
- Fixing a little but still potentially logic breaking bug.
2024-12-09 02:18:00 +01:00
qwint 1f712d9a87
Various Worlds: use / explicitly for pkgutil (#4232) 2024-12-09 01:59:40 +01:00
Scipio Wright 5b4d7c7526
TUNIC: Add Shield to Ladder Storage logic (#4146) 2024-12-09 01:58:49 +01:00
Mysteryem a948697f3a
Raft: Place locked items in create_items and fix get_pre_fill_items (#4250)
* Raft: Place locked items in create_items and fix get_pre_fill_items

`pre_fill` runs after item plando, and item plando could place an item
at a location where Raft was intending to place a locked item, which
would crash generation.

This patch moves the placement of these locked items earlier, into
`create_items`.

Setting items into `multiworld.raft_frequencyItemsPerPlayer` for each
player has been replaced with passing `frequencyItems` to the new
`place_frequencyItems` function.

`setLocationItem` and `setLocationItemFromRegion` have been moved into
the new `place_frequencyItems` function so that they can capture the
`frequencyItems` argument variable.

The `get_pre_fill_items` function could return a list of all previously
placed items across the entire multiworld which was not correct. It
should have returned the items in
`multiworld.raft_frequencyItemsPerPlayer[self.player]`. Now that these
items are placed in `create_items` instead of `pre_fill`,
`get_pre_fill_items` is no longer necessary and has been removed.

* self.multiworld.get_location -> self.get_location

Changed the occurences in the modified code.
2024-12-09 01:57:34 +01:00
qwint e3b5451672
CI: cap pytest-subtest version (#4344) 2024-12-08 20:43:16 +01:00
black-sliver 6c69f590cf
WebHost: fix host room not updating (ports in) slot table (#4308) 2024-12-08 02:22:56 +01:00
LeonarthCG c9625e1b35
Saving Princess: implement new game (#3238)
* Saving Princess: initial commit

* settings -> options

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* settings -> options

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* replace RegionData class with List[str]

RegionData was only wrapping a List[str], so we can directly use List[str]

* world: MultiWorld -> multiworld: MultiWorld

* use world's random instead of multiworld's

* use state's has_any and has_all where applicable

* remove unused StartInventory import

* reorder PerGameCommonOptions

* fix relative AutoWorld import

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* clean up double spaces

* local commands -> Local Commands

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* remove redundant which items section

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* game info rework

* clean up item count redundancy

* add game to readme and codeowners

* fix get_region_entrance return type

* world.multiworld.get -> world.get

* add more events

added events for the boss kills that open the gate, as well as for system power being restored

these only apply if expanded pool is not selected

* add client/autoupdater to launcher

* reorder commands in game info

* update docs with automated installation info

* add quick links to doc

* Update setup_en.md

* remove standalone saving princess client

* doc fixes

* code improvements and redundant default removal

as suggested by @Exempt-Medic
this includes the removal of events from the item/location name to id, as well as checking for the player name being ASCII

* add option to change launch coammnd

the LaunchCommand option is filled to either the executable or wine with the necessary arguments based on Utils.is_windows

* simplify valid install check

* mod installer improvements

now deletes possible existing files before installing the mod

* add option groups and presets

* add required client version

* update docs about cheat items pop-ups

items sent directly by the server (such as with starting inventory) now have pop-ups just like any other item

* add Steam Input issue to faq

* Saving Princess: BRAINOS requires all weapons

* Saving Princess: Download dll and patch together

Previously, gm-apclientpp.dll was downloaded from its own repo
With this update, the dll is instead extracted from the same zip as the game's patch

* Saving Princess: Add URI launch support

* Saving Princess: goal also requires all weapons

given it's past brainos

* Saving Princess: update docs

automatic connection support was added, docs now reflect this

* Saving Princess: extend([item]) -> append(item)

* Saving Princess: automatic connection validation

also parses the slot, password and host:port into parameters for the game

* Saving Princess: change subprocess .run to .Popen

This keeps the game from freezing the launcher while it is running

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-12-07 11:29:27 +01:00
Nicholas Saylor ced93022b6
Adventure: Remove unused variables (#4301)
* Remove unused variables

* Provide old parameters to comment
2024-12-06 07:15:26 +01:00
Bryce Wilson f4b926ebbe
Pokemon Emerald: Exclude sacred ash post champion (#4207)
* Pokemon Emerald: Exclude sacred ash post champion

* Pokemon Emerald: Remove .value from toggle option check
2024-12-05 16:33:21 +01:00
threeandthreee 203d89d1d3
LADX: upstream logic updates (#3963)
* Fully updates requirements.py to live LADXR (#19)

* Updates dungeon2.py to LADXR-Live (#20)

No logic changes or bugfix are in this file. It is only code cleanup.

* Update dungeon1.py (#21)

- The Three of a Kind with Bomb is moved from Normal to Hard Logic

The rest is code cleanup.

lines 22-25 | 22-26 & 33 | 34 remain different in AP | Upstream with no effective difference

* Fully updates dungeon3.py to LADXR-live (#22)

Logic Changes:
- Hard mode now considers killing the enemies in the top room with pot

Everything else is cleanup.

* Fully update dungeon4.py to LADXR-live logic (#23)

Logic Changes:
- Hard Logic: Removes Feather requirement from grabbing the Pit Key
- Hell logic: new hookshot clip (line 64)
- Hell logic: hookshot spam over the first pit of crossroads, then buffer down (line 69)
- Hell logic: push block left of keyblock up, then shaq jump off the left wall and pause buffer to land on keyblock.
- Hell logic: split zol for more entities, and clip through the block left of keyblock by hookshot spam

The rest is code cleanup

* Updates dungeon5.py mostly to LADXR-Live Logic (#24)

Logic Changes:
- Hell logic: use zoomerang dashing left to get an unclipped boots superjump off the right wall over the block. reverse is push block (line 69)

The rest is cleanup.

The upstream splits the post_gohma region into pre_gohma, gohma and post_gohma. I did not implement this yet as I do not know the implications. To port this the following lines need to be changed (AP | LADXR):
18 | 18-20;
55 | 58;
65 | 68-69

* Fully update dungeon6.py logic (#25)

Logic Changes:
- Hard logic: allow damage boosting past the mini thwomps
- Glitched logic: bomb triggering elephants in two cases

Everything else is cleanup

* Fully update dungeon7.py to LADXR-live logic (#26)

Logic Changes:
- Hard logic: Three of a Kind is now possible with bombs only

Everything else is code cleanup

* Fully updates dungeon8.py to LADXR-live (#27)

Logic change:
- Hard logic: allows to drop the Gibdos into holes as a way to kill them
- Glitched logic: underground section with fire balls jumping up out of lava. Use boots superjump off left wall to jump over the pot blocking the way


The rest is code cleanup

* Fully update dungeonColor.py to LADXR-live (#28)

Logic changes:
- Normal logic: Karakoros now need power bracelet to put them into their holes
- Hard logic: Karakoros without power bracelet but with weapon
- Hell logic: Karakoros with only bombs

Everything else is code cleanup

* Updating overworld.py (#29)

* Updating overworld.py

This tries to update all logic of the Overworld.

Logic changes include:
- Normal logic: requires hookshot or shield to traverse Armos Cave
- Hard logic: Traverse Armos Cave with nothing (formerly normal logic)
- Hard logic: get the animal village bomb cave check with jump and boomerang
- Hard logic: use rooster to go to D7
- Lots of Jesus Rooster Jumps

I stopped counting and need to go over this again.

Also, please investigate line 474 AP because it's removed in LADXR-Upstream and I don't know why.

* remove featherless fisher under bridge from hard

it was moved to hell upstream and its already present in our code

---------

Co-authored-by: Alex Nordstrom <a.l.nordstrom@gmail.com>

* fixes

* add test messages

* Adds Pegasus Boots to the test (#31)

* Fix d6 boss_key logic (#30)

* restore hardmode logic

* higher logic fixes

* add bush requirement to the raft
in case the player needs to farm rupees to play again

---------

Co-authored-by: palex00 <32203971+palex00@users.noreply.github.com>
2024-12-05 16:32:45 +01:00
threeandthreee 4d42814f5d
LADX: more item groups, location groups, keysanity preset (#3936)
* add groups and a preset

* formatting

* typing

* alias groups for progressive items

* add bush breakers item group

* fix typo

* some manual location groups

* drop dummy dungeon items from groups
2024-12-05 12:06:52 +01:00
threeandthreee d80069385d
LADX: tweak in-game hints (#3920)
* dont show local player name in hint

* add option to disable hints

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-12-05 12:03:16 +01:00
threeandthreee 85a0d59f73
LADX: text shuffle exclusions (#3919)
* text shuffle exclusions
Exclude owl statues, library books, goal sign, signpost maze, and various rupee prices from text shuffle

* clearer variable name
2024-12-05 10:23:26 +01:00
nmorale5 58f2205304
Pokemon RB: Fix Incorrect Hidden Item Location in Seafoam Islands B2F (#4304) 2024-12-05 07:48:33 +01:00
Nicholas Saylor 769fbc55a9
HK: Remove unused variables and imports (#4303)
* Remove unused variables and imports

* Accidental duplication
2024-12-04 08:51:56 +01:00
NewSoupVi f43fa612d5
The Witness: Another small access rule optimisation #4256 2024-12-04 05:39:29 +01:00
Exempt-Medic 5b0de6b6c7
FFMQ: No Longer Allow Inaccessible Useful Items (#4323)
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2024-12-03 22:51:58 +01:00
threeandthreee ac8a206d46
LADX: combine warp options (#4325)
* combine warp options

* fix

* fix typo

* mark old options as removed
2024-12-03 06:59:55 +01:00
Jouramie 6896d631db
Stardew Valley: Fix a bug in equals between Or and And rules #4326 2024-12-03 06:23:13 +01:00
Nicholas Saylor 6f2e1c2a7e
Lingo: Optimize imports and remove unused parameter (#4305) 2024-12-03 03:02:18 +01:00
Fabian Dill ffe0221deb
Core: log process ID (#4290) 2024-12-03 03:00:56 +01:00
Bryce Wilson 18e8d50768
Pokemon Emerald: Clean up dexsanity spoiler and hints (#3832)
* Pokemon Emerald: Clean up dexsanity spoiler and hints

* Pokemon Emerald: Add +, do less hacks

* Pokemon Emerald: Update changelog

* Pokemon Emerald: Replace arrow with word in changelog

* Pokemon Emerald: Fix changelog
2024-12-03 02:52:20 +01:00
Mysteryem 81b9a53a37
KH2: Add missing indirect conditions for Final region access (#3923)
* KH2: Add missing indirect conditions for Final region access

Entrances to the Final region require being able to reach any one of a
number of locations, but for a location to be reachable, its parent
region must also be reachable, so indirect conditions must be added for
these regions.

* Use World.get_location

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Use World.get_location, for real this time

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-12-03 02:51:10 +01:00
Star Rauchenberger b6ab91fe4b
LADX: Remove duplicate Magnifying Lens item (#3684)
* LADX: Magnifying Glass fixes

Removed the duplicate item (Magnifying Lens), and made the real one a filler item.

* Update worlds/ladx/Items.py

Co-authored-by: threeandthreee <alex@3and3.dev>

---------

Co-authored-by: threeandthreee <alex@3and3.dev>
2024-12-03 02:50:30 +01:00
Emily f26cda07db
Core: Hint Priority fixes (#4315)
* Update hint priority docs

* Update network protocol.md

* Add error on `UpdateHint` trying to change to `HINT_FOUND`

* Update network protocol.md

* fix: precollected hint priority
2024-12-01 15:16:36 +01:00
Fabian Dill ecc3094c70
Launcher: launch without delay on URI without choice (#4279) 2024-12-01 08:33:43 +01:00
Benjamin S Wolf 17b3ee6eaf
Core: warn if a yaml is empty (#4117)
* Core: warn if a yaml is empty

* WebHost: ignore empty yaml

Generate: log which yaml documents are empty

* Actually remove empty yamls from weight_cache

* More verbose variable name

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-12-01 05:18:00 +01:00
Exempt-Medic 284e7797c5
Adventure: create_item AttributeError -> KeyError #4219 2024-12-01 05:10:43 +01:00
Exempt-Medic 62ce42440b
Super Metroid: KeyError on invalid item name #4222 2024-12-01 05:03:13 +01:00
Natalie Weizenbaum 7b755408fa
DS3: Clarify location names for Yoel and Yuria items (#3881)
* DS3: Clarify location names for Yoel and Yuria items

* Fix encodings for `detailed_location_descriptions.py`

* Fix one more typo
2024-12-01 05:00:06 +01:00
Alex Nordstrom ed721dd0c1
LADX: Implement various upstream adjustments (#3829)
* magnifying lens changes

https://github.com/daid/LADXR/pull/156

* restore enemy visibility in mermaid statue cave

https://github.com/daid/LADXR/pull/155

* mermaid statue scale bugfix

https://github.com/daid/LADXR/pull/163

* restore vanilla map when rooster is an item

https://github.com/daid/LADXR/pull/132

* fix

* fixes to magnifying lens changes

* load marin singing even if you have marin date
4feb3099a3

* Revert "load marin singing even if you have marin date"

This reverts commit a7a546ed3f7a2b9c9bcb095984cc64319a4f7855.

* always patch tradequest
not upstream, but included in this PR because it touches the same parts of the code. https://discord.com/channels/731205301247803413/1227373762412937347

* marin date fix

* fix logic
2024-12-01 04:58:10 +01:00
Benjamin S Wolf 1a5d22ca78
Core: Add new error message for item count when defined as a set instead of a dict (#4100)
* Core: New error message if item count is a set

* Apply suggestion for error message

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Apply item count error suggestion

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
2024-12-01 04:51:26 +01:00
josephwhite 21dbfd2472
Multiserver: Add argument for timestamping STDOUT (#4266)
* core: add server arg for timestamping STDOUT

* Multiserver: Implicitly use default write_mode arg in init_logging

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-12-01 04:33:36 +01:00
Jarno 472d2d5406
Timespinner: Implemented support for universal tracker (#3771)
* Implemented slot data interpretation

* Fixed talaria attached to be taken into logic
2024-12-01 04:11:45 +01:00
Kaito Sinclaire 3af2b1dc66
id Tech 1 games: Add command line instructions/info (#3757) 2024-12-01 04:10:43 +01:00
Eric Newport 6cfc3a4667
Docs: Improved sm64ex advanced setup docs (#3741)
* Improved sm64ex advanced setup docs

This edit clarifies some things that are not obvious in the version that is currently live on the site.

This should prevent others from needing to go spelunking in Discord chat history to figure out how to do advanced builds.

* Update worlds/sm64ex/docs/setup_en.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* copyediting

---------

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
2024-12-01 04:10:00 +01:00
Rensen3 992657750c
YGO06: add Item groups (#3737)
* YGO06: adds item groups

* YGO06: Change lists to sets

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* YGO06: fix imports

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2024-12-01 04:09:22 +01:00
Jouramie a67688749f
Stardew Valley: Refactor skill progression to use new feature system (#3662)
* create a first draft of the feature

* use feature in items and locations

* add content to more places

* use feature in logic

* replace option check by feature

* remove unused code

* remove weird white space

* some import nitpicking

* flip negative if
2024-12-01 03:52:07 +01:00
Kaito Sinclaire f735416bda
id Tech 1: Clean up difficulty options (#4298) 2024-12-01 03:46:34 +01:00
palex00 e5374eb8b8
[PKMN RB] Make Encounters in one location unique (#3994)
* Makes encounters in a location generate unique Pokémon

* vyneras actually got it to work

* V5 Update Fix Part 1

* Part 2

* final puzzle piece
2024-12-01 03:22:02 +01:00
black-sliver b83b48629d
Core: rework python version check (#4294)
* Docs: update min required version

and add comment about security.

* Core: rework python version check

* CI: set min micro update for build and release
2024-11-30 17:23:28 +01:00
Exempt-Medic ca6792a8a7
Blasphemous: Add start_inventory_from_pool (#4217) 2024-11-30 16:08:41 +01:00
qwint 7cbd50a2e6
HK: add item group for dream nail(s) (#4069) 2024-11-30 16:02:32 +01:00
Fabian Dill d6da3bc899
Factorio: add Atomic Cliff Remover Trap (#4282) 2024-11-30 06:53:28 +01:00
Fabian Dill 9eaca95277
WebHost: add a page to manage session cookie (#4173) 2024-11-30 04:11:28 +01:00
Fabian Dill c1b27f79ac
Core: cull events from multidata spheres (#3623)
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2024-11-30 04:11:03 +01:00
Fabian Dill 0705f6e6c0
Factorio: option groups (#4293) 2024-11-30 04:08:17 +01:00
qwint a537d8eb65
Launcher: support Component icons inside apworlds (#3629)
* Add kivy overrides to allow AsyncImage source paths of the format ap:worlds.module/subpath/to/data.png that use pkgutil to load files from within an apworld

* Apply suggestions from code review

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

* change original-load variable name for clarity per review

* add comment to record pkgutil format

* remove dependency on PIL

* i hate typing

---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2024-11-30 03:58:52 +01:00
qwint 845a604955
MultiServer: !status shows Ready status (#3598)
* Makes !status show a note if the slot is in Status Ready

* update variable name for better clarity
2024-11-30 03:40:14 +01:00
NewSoupVi 7adb673a80
Core: "Fix" Priority Fill (#3592)
* Priority fill -> Don't use one item per player

* fix unit test thing

* Ok, I think this should do it properly
2024-11-30 03:37:08 +01:00
lordlou 72e88bb493
SMZ3: generate without rom (#3461)
* - SM now displays message when getting an item outside for someone else (fills ROM item table)

This is dependant on modifications done to sm_randomizer_rom project

* First working MultiWorld SM

* some missing things:

- player name inject in ROM and get in client
- end game get from ROM in client
- send self item to server
- add player names table in ROM

* replaced CollectionState inheritance from SMBoolManager with a composition of an array of it (required to generation more than one SM world, which is still fails but is better)

* - reenabled balancing

* post rebase fixes

* updated SmClient.py

* + added VariaRandomizer LICENSE

* + added sm_randomizer_rom project (which builds sm.ips)

* Moved VariaRandomizer and sm_randomizer_rom projects inside worlds/sm and done some cleaning

* properly revert change made to CollectionState and more cleaning

* Fixed multiworld support patch not working with VariaRandomizer's

* missing file commit

* Fixed syntax error in unused code to satisfy Linter

* Revert "Fixed multiworld support patch not working with VariaRandomizer's"

This reverts commit fb3ca18528bb331995e3d3051648c8f84d04c08b.

* many fixes and improovement

- fixed seeded generation
- fixed broken logic when more than one SM world
- added missing rules for inter-area transitions
- added basic patch presence for logic
- added DoorManager init call to reflect present patches for logic
- moved CollectionState addition out of BaseClasses into SM world
- added condition to apply progitempool presorting only if SM world is present
- set Bosses item id to None to prevent them going into multidata
- now use get_game_players

* first working (most of the time) progression generation for SM using VariaRandomizer's rules, items, locations and accessPoint (as regions)

* first working single-world randomized SM rom patches

* - SM now displays message when getting an item outside for someone else (fills ROM item table)

This is dependant on modifications done to sm_randomizer_rom project

* First working MultiWorld SM

* some missing things:

- player name inject in ROM and get in client
- end game get from ROM in client
- send self item to server
- add player names table in ROM

* replaced CollectionState inheritance from SMBoolManager with a composition of an array of it (required to generation more than one SM world, which is still fails but is better)

* - reenabled balancing

* post rebase fixes

* updated SmClient.py

* + added VariaRandomizer LICENSE

* + added sm_randomizer_rom project (which builds sm.ips)

* Moved VariaRandomizer and sm_randomizer_rom projects inside worlds/sm and done some cleaning

* properly revert change made to CollectionState and more cleaning

* Fixed multiworld support patch not working with VariaRandomizer's

* missing file commit

* Fixed syntax error in unused code to satisfy Linter

* Revert "Fixed multiworld support patch not working with VariaRandomizer's"

This reverts commit fb3ca18528bb331995e3d3051648c8f84d04c08b.

* many fixes and improovement

- fixed seeded generation
- fixed broken logic when more than one SM world
- added missing rules for inter-area transitions
- added basic patch presence for logic
- added DoorManager init call to reflect present patches for logic
- moved CollectionState addition out of BaseClasses into SM world
- added condition to apply progitempool presorting only if SM world is present
- set Bosses item id to None to prevent them going into multidata
- now use get_game_players

* Fixed multiworld support patch not working with VariaRandomizer's

Added stage_fill_hook to set morph first in progitempool
Added back VariaRandomizer's standard patches

* + added missing files from variaRandomizer project

* + added missing variaRandomizer files (custom sprites)

+ started integrating VariaRandomizer options (WIP)

* Some fixes for player and server name display

- fixed player name of 16 characters reading too far in SM client
- fixed 12 bytes SM player name limit (now 16)
- fixed server name not being displayed in SM when using server cheat ( now displays RECEIVED FROM ARCHIPELAGO)
- request: temporarly changed default seed names displayed in SM main menu to OWTCH

* Fixed Goal completion not triggering in smClient

* integrated VariaRandomizer's options into AP (WIP)

- startAP is working
- door rando is working
- skillset is working

* - fixed itemsounds.ips crash by always including nofanfare.ips into multiworld.ips (itemsounds is now always applied and "itemsounds" preset must always be "off")

* skillset are now instanced per player instead of being a singleton class

* RomPatches are now instanced per player instead of being a singleton class

* DoorManager is now instanced per player instead of being a singleton class

* - fixed the last bugs that prevented generation of >1 SM world

* fixed crash when no skillset preset is specified in randoPreset (default to "casual")

* maxDifficulty support and itemsounds removal

- added support for maxDifficulty
- removed itemsounds patch as its always applied from multiworld patch for now

* Fixed bad merge

* Post merge adaptation

* fixed player name length fix that got lost with the merge

* fixed generation with other game type than SM

* added default randoPreset json for SM in playerSettings.yaml

* fixed broken SM client following merge

* beautified json skillset presets

* Fixed ArchipelagoSmClient not building

* Fixed conflict between mutliworld patch and beam_doors_plms patch

- doorsColorsRando now working

* SM generation now outputs APBP

- Fixed paths for patches and presets when frozen

* added missing file and fixed multithreading issue

* temporarily set data_version = 0

* more work

- added support for AP starting items
- fixed client crash with gamemode being None
- patch.py "compatible_version" is now 3

* commited missing asm files

fixed start item reserve breaking game (was using bad write offset when patching)

* Nothing item are now handled game-side. the game will now skip displaying a message box for received Nothing item (but the client will still receive it).

fixed crash in SMClient when loosing connection to SNI

* fixed No Energy Item missing its ID

fixed Plando

* merge post fixes

* fixed start item Grapple, XRay and Reserve HUD, as well as graphic beams (except ice palette color)

* fixed freeze in blue brinstar caused by Varia's custom PLM not being filled with proper Multiworld PLM address (altLocsAddresses)

* fixed start item x-ray HUD display

* Fixed start items being sent by the server (is all handled in ROM)

Start items are now not removed from itempool anymore
Nothing Item is now local_items so no player will ever pickup Nothing. Doing so reduces contribution of this world to the Multiworld the more Nothing there is though.
Fixed crash (and possibly passing but broken) at generation where the static list of IPSPatches used by all SM worlds was being modified

* fixed settings that could be applied to any SM players

* fixed auth to server only using player name (now does as ALTTP to authenticate)

* - fixed End Credits broken text

* added non SM item name display

* added all supported SM options in playerSettings.yaml

* fixed locations needing a list of parent regions (now generate a region for each location with one-way exits to each (previously) parent region

did some cleaning (mainly reverts on unnecessary core classes

* minor setting fixes and tweaks

- merged Area and lightArea settings
- made missileQty, superQty and powerBombQty use value from 10 to 90 and divide value by float(10) when generating
- fixed inverted layoutPatch setting

* added option start_inventory_removes_from_pool

fixed option names formatting
fixed lint errors
small code and repo cleanup

* Hopefully fixed ROR2 that could not send any items

* - fixed missing required change to ROR2

* fixed 0 hp when respawning without having ever saved (start items were not updating the save checksum)

* fixed typo with doors_colors_rando

* fixed checksum

* added custom sprites for off-world items (progression or not)

the original AP sprite was made with PierRoulette's SM Item Sprite Utility by ijwu

* - added missing change following upstream merge

- changed patch filename extension from apbp to apm3 so patch can be used with the new client

* added morph placement options: early means local and sphere 1

* fixed failing unit tests

* - fixed broken custom_preset options

* - big cleanup to remove unnecessary or unsupported features

* - more cleanup

* - moved sm_randomizer_rom and all always applied patches into an external project that outputs basepatch.ips

- small cleanup

* - added comment to refer to project for generating basepatch.ips (https://github.com/lordlou/SMBasepatch)

* fixed g4_skip patch that can be not applied if hud is enabled

* - fixed off world sprite that can have broken graphics (restricted to use only first 2 palette)

* - updated basepatch to reflect g4_skip removal

- moved more asm files to SMBasepatch project

* - tourian grey doors at baby metroid are now always flashing (allowing to go back if needed)

* fixed wrong path if using built as exe

* - cleaned exposed maxDifficulty options

- removed always enabled Knows

* Merged LttPClient and SMClient into SNIClient

* added varia_custom Preset Option that fetch a preset (read from a new varia_custom_preset Option) from varia's web service

* small doc precision

* - added death_link support

- fixed broken Goal Completion
- post merge fix

* - removed now useless presets

* - fixed bad internal mapping with maxDiff

- increases maxDiff if only Bosses is preventing beating the game

* - added support for lowercase custom preset sections (knows, settings and controller)

- fixed controller settings not applying to ROM

* - fixed death loop when dying with Door rando, bomb or speed booster as starting items

- varia's backup save should now be usable (automatically enabled when doing door rando)

* -added docstring for generated yaml

* fixed bad merge

* fixed broken infinity max difficulty

* commented debug prints

* adjusted credits to mark progression speed and difficulty as Non Available

* added support for more than 255 players (will print Archipelago for higher player number)

* fixed missing cleanup

* added support for 65535 different player names in ROM

* fixed generations failing when only bosses are unreachable

* - replaced setting maxDiff to infinity with a bool only affecting boss logics if only bosses are left to finish

* fixed failling generations when using 'fun' settings

Accessibility checks are forced to 'items' if restricted locations are used by VARIA following usage of 'fun' settings

* fixed debug logger

* removed unsupported "suits_restriction" option

* fixed generations failing when only bosses are unreachable (using a less intrusive approach for AP)

* - fixed deathlink emptying reserves

- added death_link_survive option that lets player survive when receiving a deathlink if the have non-empty reserves

* - merged death_link and death_link_survive options

* fixed death_link

* added a fallback default starting location instead of failing generation if an invalid one was chosen

* added Nothing and NoEnergy as hint blacklist

added missing NoEnergy as local items and removed it from progression

* now doesnt require ROM for generation

* removed stage_assert_generate

* fixed conflict with main and small cleanup
2024-11-30 03:36:00 +01:00
NewSoupVi 089b3f17a7
The Witness: Add "Panel Keys" and "Obelisk Keys" item groups #4026 2024-11-30 02:16:52 +01:00
NewSoupVi ad30e3264a
The Witness: Turn off default tests on a test that is prone to swap fails #4261 2024-11-30 02:15:50 +01:00
Jouramie e262c8be9c
Stardew Valley: Fix a bug where locations in logic would disappear from universal tracker as items get sent (#4230)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-11-30 01:46:35 +01:00
Fabian Dill 492e3a355e
WebHost: delete unused script tag (#4062) 2024-11-30 00:37:26 +01:00
qwint 1487d323cd
Core: update error message for mismatched "event" placements #4043 2024-11-30 00:01:24 +01:00
NewSoupVi dd88b2c658
The Witness: Fix unreachable locations on Longbox + Postgame #4291 2024-11-29 23:47:27 +01:00
Aaron Wagener 46dfc4d4fc
Core: Allow option groups to specify option order (#3393)
* Core: Allow option groups to specify option order

* words hard

* Actually use the earlier built dictionary for faster in checking

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2024-11-29 23:37:14 +01:00
Exempt-Medic b0a61be9df
Tests: Add test that local/non local items aren't modified late #3976 2024-11-29 22:57:35 +01:00
palex00 7c00c9a49d
Core: Change "Unreachable Items" to "Unreachable progression items" in playthrough warning for clarification (#4287) 2024-11-29 22:48:01 +01:00
Kaito Sinclaire 1365bd7a0a
CODEOWNERS: Add KScl as world maintainer for id Tech 1 games (#4288) 2024-11-29 22:46:38 +01:00
David St-Louis 6e5adc7abd
New Game: Faxanadu (#3059) 2024-11-29 22:45:36 +01:00
NewSoupVi c97e4866dd
Core: Rewrite start inventory from pool code (#3778)
* Rewrite start inventory from pool code

* I think this is nicer?

* lol

* I just made it even shorter and nicer

* comments :D

* I think this makes more logical sense

* final change I promise

* HOLD UP THIS IS SO SHORT NOW

* ???????? Vi pls

* ???????? Vi pls????????????????

* this was probably important idk

* Lmao this just did not work correctly at all
2024-11-29 22:43:01 +01:00
Exempt-Medic 8444ffa0c7
id Tech: Standardizing and fixing display names (#4240) 2024-11-29 21:34:14 +01:00
Doug Hoskisson 2fb59d39c9
Zillion: use "new" settings api and cleaning (#3903)
* Zillion: use "new" settings api and cleaning

* python 3.10 typing update

* don't separate assignments of item link players
2024-11-29 21:25:01 +01:00
Doug Hoskisson b5343a36ff
Core: fix settings API for removal of Python 3.8, 3.9 (#4280)
* Core: fix settings API for removal of Python 3.8, 3.9

This is fixing 2 problems:
- The `World` class has the annotation:
  `settings: ClassVar[Optional["Group"]]`
  so `MyWorld.settings` should not raise an exception like it does for some worlds.
  With the `Optional` there, it looks like it should return `None` for the worlds that don't use it. So that's what I changed it to.

- `Group.update` had some code that required `typing.Union` instead of the Python 3.10 `|` for unions.

added unit test for this fix
added change in Zillion that I used to discover this problem and used it to test the test

* fix copy-pasted stuff

* tuple instead of set

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2024-11-29 21:17:56 +01:00
black-sliver d7a0f4cb4c
CI: fix naming of windows build action (#4286) 2024-11-29 20:49:36 +01:00
Ehseezed 77d35b95e2
Timespinner: Update AP to have parity with standalone options (#3805) 2024-11-29 20:46:12 +01:00
NewSoupVi b605fb1032
The Witness: Make Elevators Come To You an OptionSet (#4000)
* Split elevators come to you

* .

* unit test

* mypy stuff

* Fine. I'll fix the fcking commented out code. Happy?

* ruff

* """""Backwards compatibility"""""

* ruff

* make it look better

* #

* fix presets

* fix a unit test

* Make that explicit in the code

* Improve description
2024-11-29 20:45:44 +01:00
NewSoupVi a5231a27cc
Yacht Dice: Mark YachtWeights.py as "linguist-generated" (#3898)
This means its diff will be collapsed by default on PRs that change it, because it is an "auto generated" file that does not need to be looked at by reviewers
2024-11-29 20:45:10 +01:00
qwint 1454bacfdd
HK: better error messaging for charm plando (#3907) 2024-11-29 20:43:33 +01:00
Jouramie ed4e44b994
Stardew Valley: Remove some events for a slight performance increase (#4085) 2024-11-29 20:41:26 +01:00
Benjamin S Wolf d36c983461
Core: Log warnings at call site, not Utils itself (#4229) 2024-11-29 20:40:02 +01:00
black-sliver 05aa96a335
CI: use py3.12 for the linux and windows builds (#4284)
* CI: use py3.12 for the linux build

* CI: use py3.12 for the windows build
2024-11-29 20:07:14 +01:00
Bryce Wilson 6f2464d4ad
Pokemon Emerald: Rework tags/dynamically create item and location groups (#3263)
* Pokemon Emerald: Rework location tags to categories

* Pokemon Emerald: Rework item tags, automatically create item/location groups

* Pokemon Emerald: Move item and location groups to data.py, add some regional location groups

* Map Regions

* Pokemon Emerald: Fix up location groups

* Pokemon Emerald: Move groups to their own file

* Pokemon Emerald: Add meta groups for location groups

* Pokemon Emerald: Fix has_group using updated item group name

* Pokemon Emerald: Add sanity check for maps in location groups

* Pokemon Emerald: Remove missed use of location.tags

* Pokemon Emerald: Reclassify white and black flutes

* Pokemon Emerald: Update changelog

* Pokemon Emerald: Adjust changelog

---------

Co-authored-by: Tsukino <16899482+Tsukino-uwu@users.noreply.github.com>
2024-11-29 09:24:24 +01:00
ken 91185f4f7c
Core: Add timestamps to logging for seed generation (#3028)
* Add timestamps to logging for improved debugging

* Add datetime to general logging; particularly useful for large seeds.

* Move console timestamps from Main to Utils.init_logging (better location)

* Update Main.py

remove spurious blank line

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

---------

Co-authored-by: Zach Parks <zach@alliware.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
2024-11-29 07:16:54 +01:00
NewSoupVi 1371c63a8d
Core: Actually take item from pool when plandoing from_pool (#2420)
* Actually take item from pool when plandoing from_pool

* Remove the awkward index thing

* oops left a comment in

* there wasn't a line break here before

* Only remove if actually found, check against player number

* oops

* Go back to index based system so we can just remove at the end

* Comment

* Fix error on None

* Update Fill.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-11-29 07:14:23 +01:00
Fabian Dill 30b414429f
LTTP: sort of use new options system (#3764)
* LttP: switch to dataclass options definition

* LttP: write old options onto multiworld
LttP: use World.random
2024-11-29 05:02:26 +01:00
Solidus Snake ce210cd4ee
SMZ3: Add Start Inventory From Pool (#4252)
* Add Start Inventory From Pool

Just as the title implies

* Update Options.py

Fix dataclass since I had just pulled changes from prior options.py without seeing if anythin had changed

* Update Options.py

One more time with feeling

* Update worlds/smz3/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-11-29 02:16:50 +01:00
BootsinSoots 8923b06a49
Webhost: Make YGO 06 setup title match page #4262
Make Guide title match the rest of the set up guides on the webhost
2024-11-29 02:16:12 +01:00
Emily b783eab1e8
Core: Introduce 'Hint Priority' concept (#3506)
* Introduce 'Hint Priority' concept

* fix error when sorting hints while not connected

* fix 'found' -> 'status' kivy stuff

* remove extraneous warning

this warning fired if you clicked to select or toggle priority of any hint, as you weren't clicking on the header...

* skip scanning individual header widgets when not clicking on the header

* update hints on disconnection

* minor cleanup

* minor fixes/cleanup

* fix: hints not updating properly for receiving player

* update re: review

* 'type() is' -> 'isinstance()'

* cleanup, re: Jouramie's review

* Change 'priority' to 'status', add 'Unspecified' and 'Avoid' statuses, update colors

* cleanup

* move dicts out of functions

* fix: new hints being returned when hint already exists

* fix: show `Found` properly when hinting already-found hints

* import `Hint` and `HintStatus` directly from `NetUtils`

* Default any hinted `Trap` item to be classified as `Avoid` by default

* add some sanity checks

* re: Vi's feedback

* move dict out of function

* Update kvui.py

* remove unneeded dismiss message

* allow lclick to drop hint status dropdown

* underline hint statuses to indicate clickability

* only underline clickable statuses

* Update kvui.py

* Update kvui.py

---------

Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-11-29 02:10:31 +01:00
Fabian Dill b972e8c071
Core: fix deprecation warning for utcnow() in setup.py (#4170) 2024-11-29 01:57:18 +01:00
josephwhite faeb54224e
Super Mario 64: Option groups (#4161)
* sm64ex: add option groups

* sm64ex: rename sanity options group to item options

* sm64ex: rename sanity options group to logic options

* sm64ex: seperate star costs from goal options and add entrance rando to logic options

* sm64ex: seperate ability options from logic options group
2024-11-29 01:45:26 +01:00
Justus Lind 1ba7700283
Muse Dash: Change AttributeError to KeyError when Create_Item receives an item name that doesn't exist in the world (#4215)
* Change missing attribute error to key error.

* Swap to explicit key error

* Revert "Swap to explicit key error"

This reverts commit 719255891e543d15720b6bdeb293621266618efc.
2024-11-29 01:44:21 +01:00
NewSoupVi 710cf4ebba
Core: Add __iter__ to VerifyKeys (#3550)
* Add __iter__ to VerifyKeys

* Typing
2024-11-29 01:42:08 +01:00
NewSoupVi 82260d728f
The Witness: Add Fast Travel Option (#3766)
* add unlockable warps

* Change Swamp Near Platform to Swamp Platform

* apply changes to variety as well
2024-11-29 01:41:40 +01:00
NewSoupVi 62e4285924
Core: Make region.add_exits return the created Entrances (#3885)
* Core: Make region.add_exits return the created Entrances

* Update BaseClasses.py

* Update BaseClasses.py

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2024-11-29 01:41:13 +01:00
Exempt-Medic ce78c75999
OoT: Turn Logic Tricks into an OptionSet (#3551)
* Alphabetizing WebHost display for logic tricks

* Convert to a Set

* Changing this back to match upstream
2024-11-29 01:40:53 +01:00
Exempt-Medic c022c742b5
Core: Add item.filler helper (#4081)
* Add filler helper

* Update BaseClasses.py
2024-11-29 01:38:53 +01:00
Mysteryem 3cb5219e09
Core: Fix playthrough only checking half of the sphere 0 items (#4268)
* Core: Fix playthrough only checking half of the sphere 0 items

The lists of precollected items were being mutated while iterating those
same lists, causing playthrough to skip checking half of the sphere 0
advancement items.

This patch ensures the lists are copied before they are iterated.

* Replace chain.from_iterable with two for loops for better clarity

Added a comment to `multiworld.push_precollected(item)` to explain that
it is also modifying `precollected_items`.
2024-11-29 01:38:17 +01:00
NewSoupVi 5d30d16e09
Docs: Mention explicit_indirect_conditions & "Menu" -> origin_region_name (#3887)
* Docs: Mention explicit_indirect_conditions

https://github.com/ArchipelagoMW/Archipelago/pull/3682

* Update world api.md

* Docs: "Menu" -> origin_region_name

https://github.com/ArchipelagoMW/Archipelago/pull/3682

* Update docs/world api.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update world api.md

* I just didn't do this one and then Medic approved it anyway LMAO

* Update world api.md

---------

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
2024-11-29 01:37:33 +01:00
NewSoupVi 4780fd9974
The Witness: Rename some *horrendously* named variables (#4258)
* Rename all instances of 'multi' to 'progressive' and all instances of 'prog' to 'progression'

* We do a little reordering

* More

* One more
2024-11-29 01:37:19 +01:00
LiquidCat64 3ba0576cf6
CV64: Fix the first Waterway 3HB ledge setting the flag of one of the Nitro room item locations. #4277 2024-11-29 01:36:21 +01:00
axe-y 283d1ab7e8
DLC Quest Bug Fix 50+ coin bundle basic Campaign (#4276)
* DLC Quest Bug Fix

* DLC Quest Bug Fix
2024-11-29 01:35:09 +01:00
Shiny 78bc7b8156
Docs: update Pokemon R/B spanish guide (#2672)
* Update setup_es.md

* Update setup_es.md

i'm stupid and actually didn't edit the client chose part lol
2024-11-28 21:43:58 +01:00
Lolo a07ddb4371
Docs: (Re)write french alttp setup guide and game page (#2296) 2024-11-28 17:13:14 +01:00
Tim Mahan 4395c608e8
[Docs] Update the macOS guide to match changes in core (#4265)
* Update mac_en.md

Updated the minimum version recommended to a version actually supported by AP.

* 3.13 is not in fact, supported.

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2024-11-28 08:41:13 +01:00
nmorale5 f4322242a1
Pokemon RB - Fix Incorrect Item Location in Victory Road 2F (#4260) 2024-11-28 02:43:37 +01:00
black-sliver a3711eb463
Launcher: fix detection of valid .apworld (#4272) 2024-11-28 01:46:06 +01:00
Scipio Wright 6656528d78
TUNIC: Fix missing ladder rule for library fuse #4271 2024-11-28 01:43:52 +01:00
NewSoupVi e1f16c6721
WebHost: Fix crash on advanced options when a Range option used "random" as its default (#4263) 2024-11-27 14:19:52 +01:00
Fabian Dill 334781e976
Core: purge py3.8 and py3.9 (#3973)
Co-authored-by: Remy Jette <remy@remyjette.com>
Co-authored-by: Jouramie <16137441+Jouramie@users.noreply.github.com>
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
2024-11-27 03:28:00 +01:00
NewSoupVi 6c939d2d59
The Witness: Rename "Panel Hunt Settings" to "Panel Hunt Options" (#4251)
Who let me get away with this lmao
2024-11-27 02:49:18 +01:00
agilbert1412 e882c68277
Stardew Valley - Update documentation 5.x.x links into 6.x.x links #4255 2024-11-27 02:09:53 +01:00
NewSoupVi dbf284d4b2
The Witness: Give an actual name to the new option (lol) #4238 2024-11-27 02:09:13 +01:00
agilbert1412 75624042f7
Stardew Valley: Make progressive movie theater a progression trap (#3985) 2024-11-27 00:44:33 +01:00
Ziktofel 0dade05133
SC2: Fix wrongly classified location type (#4249) 2024-11-26 00:35:24 +01:00
Exempt-Medic fcaba14b62
Zillion: Add display_name to ZillionSkill #4241 2024-11-25 19:27:31 +01:00
Exempt-Medic 6073d5e37e
Lufia2: Fix Nondeterministic Behavior #4243 2024-11-25 19:26:44 +01:00
Exempt-Medic 41a7d7eeee
HK: Fix Nondeterministic Behavior #4244 2024-11-25 19:26:21 +01:00
Exempt-Medic d3a3c29bc9
Landstalker: Fix Nondeterministic Behavior #4245 2024-11-25 19:25:55 +01:00
wildham 0ad5b0ade8
[FFMQ] Fix all checks sending on hard reset + stronger read validation check (#4242)
* Fix all checks sending on hard reset

* stronger validation

* Fix typo

* remove extraneous else

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* fix style

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-11-25 19:25:29 +01:00
Exempt-Medic e6e31a27e6
SC2: Fix Nondeterministic Behavior (#4246)
* Add < for sorting

* Sorting for determinism

* id instead of value
2024-11-25 19:25:00 +01:00
Scipio Wright a650e90b57
TUNIC: Add clarifying comment to item links handling #4233 2024-11-24 18:43:28 +01:00
gaithern 36f17111bf
Kingdom Hearts: Minor Logic Fixes (#4236)
* Update Rules.py

* Update worlds/kh1/Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2024-11-24 18:42:21 +01:00
Jarno 03b90cf39b
Timespinner: Re-added missing enmemy rando option #4235 2024-11-24 15:57:39 +01:00
Scipio Wright 5729b78504
TUNIC: Fix it so item linked locations are correct in slot data (#4105)
* Fix it so item linked locations are correct in slot data

* List -> Set

* Cache the locations instead

* Just loop the multiworld once

* Move it all to fill slot data and pretend we're doing a stage

* Move groups up so it doesn't loop over the multiworld locations if no item links are present

* Update worlds/tunic/__init__.py

Co-authored-by: Mysteryem <Mysteryem@users.noreply.github.com>

---------

Co-authored-by: Mysteryem <Mysteryem@users.noreply.github.com>
2024-11-23 01:42:44 +01:00
Mysteryem ba50c947ba
AHiT: Fix reconnecting rift access regions for starting and plando acts (#4200)
Reconnecting an act in a telescope to a time rift removes the entrances
to the time rift from its access regions because it will be accessible
from the telescope instead.

By doing so early on, as a starting act with insanity act randomizer or
as a plando-ed act, this can happen before the time rift itself has been
reconnected to an act or other time rift. In which case, when later
attempting to connect that time rift to an act or other time rift, the
entrances from the rift access regions will no longer exist, so must be
re-created. The original code was mistakenly re-creating the entrances
from the time rift being reconnected, instead of from the rift access
regions.
2024-11-23 00:13:57 +01:00
digiholic 2424b79626
OSRS: Fixes to Logic errors related to Max Skill Level determining when Regions are accessible (#4188)
* Removes explicit indirect conditions

* Changes special rules function add rule instead of setting, and call it unconditionally

* Fixes issues in rule generation that have been around but unused the whole time

* Finally moves rules out into a separate file. Fixes level-related logic

* Removes redundant max skill level checks on canoes, since they're in the skill training rules now

* For some reason, canoe logic assumed you could always walk from lumbridge to south varrock without farms. This has been fixed

* Apply suggestions from code review

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Quests now respect skill limits and can be excluded. Tasks that take multiple skills how actually check all skills

* Adds alternative route for cooking that doesn't require fishing

* Remove debug code

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-11-22 16:33:27 +01:00
Mysteryem d4b1351c99
Aquaria: Remove BaseException handling from create_item (#4218)
* Aquaria: Remove BaseException handling from create_item

Catching `BaseException` without re-raising the exception should almost
never be done because `BaseException` includes exit exceptions, such as
`SystemExit` and `KeyboardInterrupt`.

Ideally, the caught exception types should be as narrow as possible to
not mask bugs from catching unexpected exceptions. Having narrow
exception types can also help indicate to other developers what
exceptions are expected to be raisable by the code within the `try`
clause.

Similarly, the `try` clause should ideally contain the minimum code
necessary, to avoid masking bugs in the case that code within the `try`
clause that is not expected to raise an exception does so.

In this case, the only expected exception that can occur appears to be
`item_table[name]` that can raise a `KeyError` when `create_item()` is
passed an unexpected `name` argument. So this patch moves the other code
out of the `try` clause and changes the caught exception types to only
`KeyError`.

* Remove try-except

The KeyError that would be raised will be propagated as-is rather than
raising a new exception in its place.

* Remove extra newline

The original code did not have this newline, so it has been removed.
2024-11-21 20:43:37 +01:00
qwint 859ae87ec9
Launcher: ports the _stop fix in the Launcher kivy App to handle_url Popup App (#4213)
* fixes url launched popup so it can close cleanly after spawning another kivy app like text client

* whoops
2024-11-21 17:43:01 +01:00
Doug Hoskisson 124ce13da7
Core: improve error message for missing "game" entry in yaml (#4185) 2024-11-20 09:45:41 +01:00
qwint 48ea274655
MultiServer: persist hints even if previously found (#4214)
* change to persist all hints to ctx.hints regardless of found status

* remove if not found entirely as it seems like it was added to not double charge hint points
9842399d8b
2024-11-19 21:16:10 +01:00
Aaron Wagener 85a713771b
Tests: have option preset validation test do full validation (#4208)
* Tests: have option preset validation test do full validation

* sum on an IntFlag is a thing apparently
2024-11-18 18:09:27 +01:00
black-sliver 3ae8992fb6
Clients: fix high CPU usage when launched via MultiProcessing (#4209)
* Core: make Utils.stream_input not consume all CPU for non-blocking streams

* Clients: ignore MultiProcessing pipe as input console
2024-11-18 15:59:17 +01:00
Scipio Wright 01c6037562
TUNIC: Fix a few missing tricks in logic (#4132)
* Add missing connection to the furnace entry by west garden

* Add missing connection to the furnace entry by west garden

* Add missing hard ls for ruined passage door

* Allow shield for LS

* Split PR into two

* Split PR into two

* Split PR into two

* Add dark tomb ice grapple through the wall
2024-11-18 14:39:58 +01:00
agilbert1412 4b80b786e2
Stardew Valley: Removed Walnutsanity and Filler buffs from the all random preset (#4206) 2024-11-18 08:45:04 +01:00
Silvris bd5c8ec172
MM2: minor bugfixes (#4190)
* move special cases to be outside strict

* Update text.py

* fix wily machine edge case, incorrect weapons, and time stopper failsafe

* bump world version

* weakness checking is inclusive

* Update __init__.py

* add air shooter to edge case validation
2024-11-18 02:22:25 +01:00
t3hf1gm3nt baf291d7a2
TLOZ: Assorted Logic Fixes (#4203)
* TLOZ: Assorded Logic Fixes

- Add needing arrows for Pols Voice rule. Not super necessary at the moment since wooden arrows are always accessible in one of the opening shops, but future proofing for future plans

- Create Gohma Locations and make sure all Gohma blocked locations have the required rule (was missing at least one location before)

- Remove the rule requiring Bow for all locations of level 8 (not sure why that was there, it's theoretically redundant now that Gohma and Pols Voice are properly marked)

- Make sure Digdogger locations properly require Recorder, and clean up redundant Level 7 rules as level 7 currently requires Recorder to access the entrance

* Update worlds/tloz/Rules.py

forgor that has_any exists

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Remove world = multiworld

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-11-18 02:19:26 +01:00
NewSoupVi 9c102da901
The Witness: Allow setting the puzzle randomization seed yourself (#4196)
* Allow setting the puzzle randomization seed yourself

* longer tooltip

* Oh

* Also actually have the correct values that the client will accept (lol, thanks Medic)

* Update worlds/witness/options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-11-18 02:16:14 +01:00
Louis M 75e18e3cc9
Aquaria: Fixing no progression bug (#4199) 2024-11-17 16:59:50 +01:00
CaitSith2 a3d6036939
Factorio: energy link bridge improvements (#4182)
* improve energy link performance on large surfaces

* Add Energy link bridge storage table to initialization.

* Fix event based energy link for Factorio 2.0

* Adjust energy link bridge for quality.
2024-11-17 16:58:14 +01:00
Mysteryem 7eb12174b7
Core: Fix empty rule comparisons with subclasses (#4201)
If a world uses a `Location` or `Entrance` subclass that overrides the
`item_rule`/`access_rule` class attribute, then
`spot.__class__.item_rule`/`spot.__class__.access_rule` will get the
overridden rule, which may not be an empty rule.

Uses of `spot.__class__` have been replaced with getting the class
attribute rule belonging to the `Location` or `Entrance` class.
2024-11-17 16:55:42 +01:00
NewSoupVi 73146ef30c
Tests: Use Option.from_any instead of Option() in test_pickle_dumps, which is currently preventing Range options from using default: "random" #4197 2024-11-17 01:52:49 +01:00
Fabian Dill 66314de965
Subnautica: compose DeathLink custom text instead of overwriting (#4172)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-11-17 00:55:18 +01:00
Zach "Phar" Parks 5141f36e95
WebHost: Fix 500 server errors for hints involving ItemLink slots on tracker pages (#4198)
* Also makes adjustments to the style for these slots by italicizing its names (including multi-tracker).
* Player-specific trackers do not link to ItemLink player trackers (they do not exist).
* Fixes a bug on Factorio multi-tracker when item links exist.
2024-11-16 16:16:09 +00:00
black-sliver 9ba613277e
Launcher: change import order to fix ModuleUpdate (#4194) 2024-11-16 03:00:34 +01:00
black-sliver f9c6ecc8b2
Webhost: fix doc and yaml filenames / install paths (#4193)
* WebHost: use new safe yaml template filename

this mirrors the change in ArchipelagoMW/#4106 in WebHost

* WebHost: install docs into safe filename and require docs to be named safe

* Test: update doc test for safe name

* WebHost: fix import order to not break ModuleUpdate
2024-11-15 17:31:03 +01:00
Exempt-Medic a734d25f66
PKMN R/B: Don't change classification of items from other worlds #4192 2024-11-15 01:57:08 +01:00
Branden Wood 2a850261b8
docs: Add @BrandenEK as codeowner (#4177) 2024-11-14 23:57:49 +01:00
palex00 70b9b97841
[PKMN RB] Fixes faulty logic in Victory Road 1 #4191 2024-11-14 23:50:36 +01:00
gurglemurgle5 6c9b7eca10
Core: Fix Template Yamls for games with colon in name (#4106)
* add quotes around strings containing {{ game }}

* do the actually correct thing instead of a hack

thanks berserker66 for pointing out to me that I was doing this the
completly wrong way, so I fixed it up

* Clean up filenames to prevent illegal chars

* Use %s substitution instead of concatenation

* whoops

somehow i removed a space from the comment for the regex, so this adds
it back

* Use pre-existing function in Utils.py

* Test: add test for option yaml with colon

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2024-11-14 23:43:42 +01:00
Natalie Weizenbaum dd659de079
DS3: List compatible static randomizer versions in slot data (#4178)
This will make it easier for players to understand when they have a
mismatch between their DS3 apworld and their local randomizer version,
mitigating a common source of confusion and support requests.
2024-11-14 23:43:34 +01:00
LiquidCat64 7916d1e67c
CV64: Fix DeathLink Nitro explosions hitting you at times they shouldn't #4158 2024-11-14 23:41:57 +01:00
LiquidCat64 c9e63a836a
CV64: Fix some textbox message truncation issues #4157 2024-11-14 23:40:39 +01:00
Katelyn Gigante 8f60a4a259
Core: Detect and account for apworlds being downloaded with a (1) in their name (#4144)
* Core: Detect and account for apworlds being downloaded with a (1) in their name

* Reword comment

* Always use internal module name

* Requested changes from black-silver
2024-11-14 21:51:05 +01:00
Nicholas Saylor eac3e3c29e
Tests: Add ignore filter to s2clientprotocol warnings (#4180) 2024-11-13 19:04:31 +01:00
Benjamin S Wolf c295926ce1
Landstalker: remove global ref to multiworld (#4175)
* Landstalker: remove global ref to multiworld

`cached_spheres` holds a reference to the multiworld, which leaks the multiworld if multidata is skipped. Instead of making it a class variable, give a reference to each matching world.

* Switch to using `get_game_worlds`
2024-11-13 13:05:34 +01:00
CaitSith2 85159a4f1f
Factorio: Fix satellite goal (#4183) 2024-11-13 02:03:27 +01:00
Nicholas Saylor 8b87e20a96
DLCQuest: Use options API for campaign and remove unused imports in tests #4181 2024-11-13 00:13:49 +01:00
agilbert1412 17f03bb5f8
Stardew valley: Fixed furnace logic bug (#4163) 2024-11-12 05:27:43 +01:00
Hexa 74f922ea37
MMBN3: Typo for SloGauge (#3457) 2024-11-12 00:03:48 +01:00
Nicholas Saylor 10bc05a172
Update codeQL to v3 (#4143) 2024-11-11 23:50:12 +01:00
palex00 432d8fa1c2
[PKMN RB] Adds slot data that tells the tracker V5 logic should be considered (#3995)
* Adds v5_update-info to slot data

* Adds a comma

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2024-11-11 18:02:37 +01:00
Fabian Dill f3413e9cef
Factorio: support 2.0 update (#4110)
- removed tutorialization (Craft/Do X to unlock tech)
- start with  everything needed for power, electric mining drills, science lab and automation science already unlocked
- updated world gen
- updated mod api use
   - updated fluid boxes (CaitSith2)
- new option: free sample quality (needs quality mod)
- removed old gruft, faster gen speed, faster load time
- lists space age as explicitly not supported, so it prevents the game from trying to load both
- fixes Y offset of traps being wrong (way higher than intended)
- client now has a 5 second timeout to communicate with the bound factorio server, so it aborts actions if the server died
- savegames are now stored  in write_data_directory -> saves -> Archipelago
- add cargo-landing-pad  handling
- starting rocket silo and cargo landing pad respect free sample quality 
- supports Factorio 2.0

---------

Co-authored-by: CaitSith2 <d_good@caitsith2.com>
2024-11-11 11:43:16 +01:00
black-sliver b3e5ef876a
WebHost: update werkzeug (#4167) 2024-11-10 01:40:29 +01:00
black-sliver 9be996ba0e
Core: downgrade websockets and minor fixes (#4166)
* Core: downgrade websockets to 13.x

14.x currently doesn't work for MultiServer.
14.x is not supported with py3.8, so updating to 14.x should be scheduled for AP 0.6.0.

* CI: 5min timeout for hosting test

* MultiServer: properly shutdown even if ctx is invalid

* CI: increase hosting test timeout to 10min

this is 4x expected time, just to be safe.
2024-11-10 01:23:29 +01:00
NewSoupVi fa93bc5d1e
The Witness: Get rid of Menu region, prepare for other worlds to change theirs (hints) #3888 2024-11-09 21:10:54 +01:00
Justus Lind 6b4f6ebc1e
Update to Muse Dash v4.9.0 [Ensemble Arcanum] (#4095)
* Update to Muse Dash v4.9.0

* Add trailing newline

* I've forgotten to adjust this for a while. Lets increase it by a decent chunk.
2024-11-09 20:14:34 +01:00
Nicholas Saylor 930529e211
DS3: Update tests to use bases.py (#4138) 2024-11-09 19:29:51 +01:00
LiquidCat64 aae8b16073
CV64: Remove multiworld random usage #4156 2024-11-08 18:57:44 +01:00
Mysteryem f4072833f3
TUNIC: Add Shop indirect condition (#4160)
* TUNIC: Add Shop indirect condition

The `Overworld -> Cube Cave Entrance Region` Entrance checks
`can_shop()` which checks for being able to reach the "Shop" Region, so
the Entrance requires an indirect condition of reaching the "Shop"
Region.

* Rename entrance variable to cube_entrance

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2024-11-08 18:57:11 +01:00
Mysteryem f52d65a141
Pokemon RB: make stage_post_fill deterministic (#4008)
stage_post_fill iterates sets of locations, so the iteration order is
non-deterministic, resulting in different items being converted from
Progression to Useful when generating with the same seed.

This patch makes stage_post_fill deterministic by sorting the duplicate
pokemon locations in each sphere before choosing which of the duplicates
should remain as progression.
2024-11-08 12:11:41 +01:00
SunCat 2bdc1e0fc5
Checksfinder: clean up setup guide intro and change ownership #4147 2024-11-07 10:35:12 +01:00
Remy Jette 639b9598bd
sm64ex: Make the Exclamation Boxes option a Toggle (#4152) 2024-11-07 10:34:41 +01:00
NewSoupVi a29205b547
Core: Add Item.excludable helper function (#4080)
Some worlds might want to check for "Item is junk", i.e. an excludable item.

Because this is both `filler` and `trap`, and because `filler` is `0`, there are many "wrong ways" to do this. So I think we should provide a helper function for it.
2024-11-07 09:59:08 +01:00
black-sliver 345d5154a9
WebHost: fix missing timezone in tracker if-modified-since handling (#4125)
* WebHost: fix missing timezone in tracker if-modified-since handling

and add a test for it

* WebHost, Test: fix running test_tracker in parallel
2024-11-07 09:51:40 +01:00
black-sliver a0207e0286
Setup: exclude zstandard (#4155)
This is quite the big dependency (~20MB) that is unused.
For non-webhost it is an optional dependency to requests.
2024-11-07 09:41:42 +01:00
Mysteryem 7449bf6b99
ALttP: Use auto indirect conditions (#4153)
ALttP makes common use of entrances with access rules that require
another entrance to be accessible. This results in requiring an indirect
condition to be registered for the other entrance's `.parent_region`,
but this indirect condition is often missing.

There are so many missing indirect conditions, and due to the complexity
of some of the chained rules, it is simply not realistic to add all the
missing indirect conditions.

This patch changes ALttP to use automatic indirect conditions instead of
explicit indirect conditions and removes the places that were
registering indirect conditions.

Without this patch, the missing indirect conditions almost never have an
effect on generating with default options, but enabling certain options,
such as `glitches_required` or `entrance_shuffle` can result in
frequently checking entrances that are missing indirect conditions.

Examples of complex chained rules:
`get_rule_to_add()` in `Rules.set_bunny_rules()` can create
rules on entrances that require access to any of a number of different
other entrances, which should require the parent regions of all of those
other entrances to be registered as indirect conditions.

There are entrance access rules that check
`StateHelpers.can_kill_most_things()` (e.g. `Turtle Rock Second Section
Bomb Wall`), which can check `can_extend_magic()`, which checks for
being able to buy unlimited `Blue Potion`, which checks for being able
to reach a shop that sells unlimited `Blue Potion`. This is usually
`Potion Shop`, but there is a yaml option that shuffles shop
inventories, so the shop that sells unlimited `Blue Potion` can be
randomized, meaning that the region that should be registered as an
indirect condition can also be randomized.

Example of many missing indirect conditions:
With `small_key_shuffle: universal`, every single
`ALttPLogic._lttp_has_key()` checks for being able to reach shops that
sell an unlimited number of universal Small Keys. Meaning that every
entrance access rule that uses `_lttp_has_key()` should register all
shop regions that sell unlimited universal small keys as indirect
conditions.
2024-11-07 09:29:47 +01:00
Nicholas Saylor 1cba694b78
Bumper Stickers: Update tests to bases.py #4137 2024-11-06 09:37:36 +01:00
Nicholas Saylor 9082ce74df
Pokemon Emerald: Update tests to use bases.py #4142 2024-11-06 09:37:14 +01:00
Nicholas Saylor 5dfb2c514f
DLC Quest: Update tests to use bases.py #4141 2024-11-06 09:36:49 +01:00
Zach "Phar" Parks e2e5c5102b
Rogue Legacy: Remove item/location id overlap rejection code. (#3893)
* Rogue Legacy: Remove item/location id overlap rejection code.

RL has been updated to support id overlaps.

* Update __init__.py

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-11-05 08:33:41 +00:00
Nicholas Saylor 08b99b8c33
LADX: Update tests to use bases.py #4139 2024-11-04 08:40:08 +01:00
Nicholas Saylor 72d2a33c0b
Lufia 2: Update tests to bases.py #4136 2024-11-04 08:39:12 +01:00
Nicholas Saylor 6d0f0d2f4a
LTTP: Update tests to use bases.py #4140 2024-11-04 08:38:47 +01:00
SunCat a64548a4c6
ChecksFinder: Update description (#4145)
* edit checksfinder description

* Remove trailing whitespace in docstring

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-11-04 08:19:34 +01:00
Nicholas Saylor d1dee226bf
Launcher: Add link to the official site #4091 2024-11-03 15:48:52 +01:00
Bryce Wilson 504eceaf4f
Pokemon Emerald: Prevent evolution fanfare from being replaced with flute (#4113)
* Pokemon Emerald: Prevent evolution fanfare from being replaced with flute

* Pokemon Emerald: Update Changelog
2024-11-03 15:36:39 +01:00
Ziktofel 96abc32f7d
SC2: Small bugfix for SC2 logic #4126 2024-11-03 15:27:04 +01:00
NewSoupVi 048658955b
Core: The Item Links fix to end them all (for now, hopefully) (#4096)
* Core: The Item Links fix to end them all

This puts the bandaid that was holding Item Links together for years back on.

It's a bad solution
But it's what we had previously, and the change away from this is what broke them

So in the interest of 0.5.1 releasing this century, maybe we should just go with this.

* Update AutoWorld.py
2024-11-03 15:22:10 +01:00
Nicholas Saylor 931e335155
Generate: Prevent ini Files from Being Included in YAML Discovery (#4127)
* Prevent ini files from being included in YAML discovery

* Update Generate.py

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2024-11-01 21:07:43 +01:00
Nicholas Saylor 1323474a52
Tests: Update test_fill.py to use Options API (#4128)
* Update test_fill.py::TestDistributeItemsRestrictive::test_non_excluded_local_items

* Update test_fill.py:TestBalanceMultiworldProgression
2024-11-01 12:43:28 +01:00
black-sliver f7b9ac990b
WebHost: improve image asset loading performance (#4123)
* WebHost: Scale image assets

* WebHost: convert images to webp
2024-10-30 23:56:39 -04:00
Doug Hoskisson 085b655ad9
SNIClient: log exceptions and keep task alive (#3911)
* SNIClient: log exceptions and keep task alive

* also log errors in `get_handler`
and disconnect if error in `game_watcher`
2024-10-31 00:16:02 +01:00
qwint 0b5c7fe8a9
HK: fix grubhunt required grubs count (#4094)
* somehow this mixup got into the final grubhunt PR

* catch a case I didn't test before

* Update worlds/hk/__init__.py

Co-authored-by: Mysteryem <Mysteryem@users.noreply.github.com>

* first pass at adding grub count tests

* add tests to explicitly show counting/not counting of player2s grubs

* forgot a test rename

---------

Co-authored-by: Mysteryem <Mysteryem@users.noreply.github.com>
2024-10-30 23:58:40 +01:00
Aaron Wagener aaf25f8c6f
Tests: add test that option classes aren't reused (#3530) 2024-10-30 23:32:38 +01:00
Aaron Wagener f00975c73d
Tests: Add a test that weights file generates different results per player correctly (#3392)
* Tests: Add a test that weights file generates different results per player correctly

* Update test/programs/test_generate.py

* Generate.main() return and accessibility options were changed
2024-10-30 23:18:30 +01:00
Star Rauchenberger ad40acd392
Lingo: Mark Eight Room -> The Incomparable as a warp (#4119) 2024-10-29 23:09:31 +01:00
Nicholas Saylor 4503ba75b6
Pokemon Emerald: Link to Rom Changes in Game Page (#4090)
* Added rematch information to game page

* Better wording

* Actually correct the language

* Update worlds/pokemon_emerald/docs/en_Pokemon Emerald.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Linked to rom_changes_en.md rather than adding to the game page

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-10-29 13:37:42 +01:00
Bryce Wilson 14c7b22fea
Pokemon Emerald: Update changelog (#4112) 2024-10-29 13:36:02 +01:00
Benjamin S Wolf 1541f46d44
oc2: Reduce calls to meets_requirements (#4060) 2024-10-29 11:07:49 +01:00
Scipio Wright b6c58c5c24
TUNIC: Minor revision to IG and LS option descriptions #4115 2024-10-29 02:43:03 +01:00
Natalie Weizenbaum 4dde3a2191
[DS3] Remind players to remove the old dinput8.dll (#4034)
This is a common mistake when players are getting set up with the new DS3 version.
2024-10-28 23:30:07 +01:00
Mysteryem edacc07808
OSRS: Add missing indirect conditions (#4029)
All entrances to Cooks_Guild and Crafting_Guild and all entrances using
special logic for canoes were missing indirect conditions for the
regions that the cooking, crafting and woodcutting skill rules require
access to.
2024-10-28 23:26:08 +01:00
Star Rauchenberger f3c59818b1
Lingo: Update documentation for panel shuffle (#4086) 2024-10-28 23:21:13 +01:00
Scipio Wright 594a8321c4
TUNIC: Add link to logic tricks doc (#4087)
* Add link to logic tricks doc

* Update worlds/tunic/docs/en_TUNIC.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-10-28 23:19:57 +01:00
Bryce Wilson f10eb850dc
Pokemon Emerald: Add some warnings to option descriptions (#4114) 2024-10-28 23:17:25 +01:00
Nicholas Saylor 3f6754d7f2
Docs: Update Information about Running Unittests (#4093)
* Expanded information in docs

* Revert run.xml changes

* Update docs/tests.md

Co-authored-by: qwint <qwint.42@gmail.com>

* Remove newline

* Apply suggestions from code review

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

* Added suggestsions from code review

---------

Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2024-10-28 19:47:08 +01:00
black-sliver 382a5df1d8
macos: fix crash when 'Open Patch' is used (#4108)
* macos: fix crash when 'Open Patch' is used

* Utils: fix error message in open_directory
2024-10-28 08:41:36 +01:00
palex00 9b5a2bedac
[KH2] Add new Poptracker Pack to the KH2 Setup Guide (#4104)
* Add new Poptracker Pack to the KH2 Setup Guide

* Match Order in description

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Make it say PopTracker with a capital T everywhere

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-10-28 02:38:05 +01:00
Spineraks d15fa57151
Yacht Dice: Textual fixes and changes (Docs / yaml description) (#3967)
* Add the yacht dice (from other git) world to the yacht dice fork

* Update .gitignore

* Removed zillion because it doesn't work

* Update .gitignore

* added zillion again...

* Now you can have 0 extra fragments

* Added alt categories, also options

* Added item categories

* Extra categories are now working! 🐶

* changed options and added exceptions

* Testing if I change the generate.py

* Revert "Testing if I change the generate.py"

This reverts commit 7c2b3df6170dcf8d8f36a1de9fcbc9dccdec81f8.

* ignore gitignore

* Delete .gitignore

* Update .gitignore

* Update .gitignore

* Update logic, added multiplicative categories

* Changed difficulties

* Update offline mode so that it works again

* Adjusted difficulty

* New version of the apworld, with 1000 as final score, always

Will still need to check difficulty and weights of adding items.
Website is not ready yet, so this version is not usable yet :)

* Changed yaml and small bug fixes

Fix when goal and max are same
Options: changed chance to weight

* no changes, just whitespaces

* changed how logic works

Now you put an array of mults and the cpu gets a couple of tries

* Changed logic, tweaked a bit too

* Preparation for 2.0

* logic tweak

* Logic for alt categories properly now

* Update setup_en.md

* Update en_YachtDice.md

* Improve performance of add_distributions

* Formatting style

* restore gitignore to APMW

* Tweaked generation parameters and methods

* Version 2.0.3

manual input option
max score in logic always 2.0.3
faster gen

* Comments and editing

* Renamed setup guide

* Improved create_items code

* init of locations: remove self.event line

* Moved setting early items to generate_early

* Add my name to CODEOWNERS

* Added Yacht Dice to the readme in list of games

* Improve performance of Yacht Dice

* newline

* Improve typing

* This is actually just slower lol

* Update worlds/yachtdice/Items.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update Options.py

* Styling

* finished text whichstory option

* removed roll and rollfragments; not used

* import; worlds not world :)

* Option groups!

* ruff styling, fix

* ruff format styling!

* styling and capitalization of options

* small comment

* Cleaned up the "state_is_a_list" a little bit

* RUFF 🐶

* Changed filling the itempool for efficiency

Now, we start with 17 extra items in the item pool, it's quite likely you need at least 17 items (~80%?).
And then afterwards, we delete items if we overshoot the target of 1000, and add items if we haven't reached an achievable score of 1000 yet. Also, no need to recompute the entire logic when adding points.

* 🐶

* Removed plando "fix"

* Changed indent of score multiplier

* faster location function

* Comments to docstrings

* fixed making location closest to goal_score be goal_score

* options format

* iterate keys and values of a dict together

* small optimization ListState

* faster collection of categories

* return arguments instead of making a list (will 🐶 later)

* Instead of turning it into a tuple, you can just make a tuple literal

* remove .keys()

* change .random and used enumerate

* some readability improvements

* Remove location "0", we don't use that one

* Remove lookup_id_to_name entirely

I for sure don't use it, and as far as I know it's not one of the mandatory functions for AP, these are item_name_to_id and location_name_to_id.

* .append instead of += for single items, percentile function changed

Also an extra comment for location ids.

* remove ) too many

* Removed sorted from category list

* Hash categories (which makes it slower :( )

Maybe I messed up or misunderstood...
I'll revert this right away since it is 2x slower, probably because of sorted instead of sort?

* Revert "Hash categories (which makes it slower :( )"

This reverts commit 34f2c1aed8c8813b2d9c58896650b82a810d3578.

* temporary push: 40% faster generation test

Small changes in logic make the generation 40% faster.
I'll have to think about how big the changes are. I suspect they are rather limited.
If this is the way to go, I'll remove the temp file and redo the YachtWeights file, I'll remove the functions there and just put the new weights here.

* Add Points item category

* Reverse changes of bad idea :)

* ruff 🐶

* Use numpy and pmf function to speed up gen

Numpy has a built-in way to sum probability mass functions (pmf).
This shaves of 60% of the generation time :D

* Revert "Use numpy and pmf function to speed up gen"

This reverts commit 9290191cb323ae92321d6c2cfcfe8c27370f439b.

* Step inbetween to change the weights

* Changed the weights to make it faster

135 -> 81 seconds on 100 random yamls

* Adjusted max_dist, split dice_simulation function

* Removed nonlocal and pass arguments instead

* Change "weight-lists" to Dict[str, float]

* Removed the return from ini_locations.

Also added explanations to cat_weights

* Choice options; dont'use .value (will ruff later)

* Only put important options in slotdata

* 🐶

* Add Dict import

* Split the cache per player, limit size to 400.

* 🐶

* added , because of style

* Update apworld version to 2.0.6

2.0.5 is the apworld I released on github to be tested
I never separately released 2.0.4.

* Multiple smaller code improvements

- changed names in YachtWeights so we don't need to translate them in Rules anymore
- we now remember which categories are present in the game, and also put this in slotdata. This we do because only one of two categories is present in a game. If for some reason both are present (plando/getitem/startinventory), we now know which category to ignore
-

* 🐶 ruff

* Mostly minimize_extra_items improvements

- Change logic, generation is now even faster (0.6s per default yaml).
- Made the option 'minimize_extra_items' do a lot more, hopefully this makes the impact of Yacht Dice a little bit less, if you want that. Here's what is also does now:
 - you start with 2 dice and 2 rolls
 - there will be less locations/items at the start of you game

* ruff 🐶

* Removed printing options

* Reworded some option descriptions

* Yacht Dice: setup: change release-link to latest

On the installation page, link to the latest release, instead of the page with all releases

* Several fixes and changes

-change apworld version
-Removed the extra roll (this was not intended)
-change extra_points_added to a mutable list to that it actually does something
-removed variables multipliers_added and items_added
-Rules, don't order by quantity, just by mean_score
-Changed the weights in general to make it faster

* 🐶

* Revert setup to what it was (latest, without S)

* remove temp weights file, shouldn't be here

* Made sure that there is not too many step score multipliers.

Too many step score multipliers lead to gen fails too, probably because you need many categories for them to actually help a lot. So it's hard to use them at the start of the game.

* add filler item name

* Textual fixes and changes

* Remove Victory item and use event instead.

* Revert "Remove Victory item and use event instead."

This reverts commit c2f7d674d392a3acbc1db8614411164ba3b28bff.

* Changed order of options

Also changed 'both options' to 'the website'

* Rephrase the offline-play part

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-10-28 02:37:21 +01:00
PoryGone b27f667a15
Core: Add Version string to Launcher title (#4107) 2024-10-28 01:53:11 +01:00
Natalie Weizenbaum 579abb33c0
Properly fall back to a world's `rich_text_options_doc` (#4109)
Previously, because `default(..., true)` only checks if the
left-hand-side is falsey, not just `None`, this always forced options
to render in non-rich mode if they were explicitly set to
`rich_text_doc = None`. Now it matches the intended and documented
behavior, where `None` falls back to the world's
`rich_text_options_doc` setting.
2024-10-28 00:01:41 +01:00
Nicholas Saylor daad3d0350
SM64ex: Add links to documentation for makeflags and patches #4092 2024-10-27 01:31:56 +02:00
black-sliver d61a76fb02
Setup: SNI: separate win7/non-win7 build, update macos naming (#4088)
* Setup: fix macos SNI download name

* Setup: prefer SNI Windows7 build on py3.8, non-7 on py3.9+
2024-10-27 00:28:47 +02:00
black-sliver 5d4684f315
WebHost: restore fragment links for glossary and faq and make titles clickable (#4103)
* WebHost: restore fragment links for glossary and faq

such as /faq/en/#what-does-multi-game-mean

* WebHost: faq, glossary: make markdown titles clickable
2024-10-26 23:10:38 +02:00
Silvris cd7b1df650
OoT: fix plando/item links (again) #4098 2024-10-26 06:25:03 +02:00
qwint af77b76265
Core: fix item links for alternate menu regions #4097 2024-10-26 05:59:28 +02:00
black-sliver 77ee6d73bc
Setup: more typing (#4089) 2024-10-25 08:51:53 +02:00
Scipio Wright 33daebef57
TUNIC: Add prog + useful to some items #4066 2024-10-23 02:30:31 +02:00
Nocallia 05ec14e23c
HK: Replace "Hook" in PreciseMovement description to "Claw" (#4078) 2024-10-23 01:26:04 +02:00
Silvris 049a8780b5
Core: fix pickling plando connections (#4054)
* shift plando pickle hack

* Update Utils.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-10-22 21:08:25 +02:00
Spineraks 703e3393a6
Yacht Dice: Fix logic (again) so that score doesn't drop when receiving item (#4044)
* Add the yacht dice (from other git) world to the yacht dice fork

* Update .gitignore

* Removed zillion because it doesn't work

* Update .gitignore

* added zillion again...

* Now you can have 0 extra fragments

* Added alt categories, also options

* Added item categories

* Extra categories are now working! 🐶

* changed options and added exceptions

* Testing if I change the generate.py

* Revert "Testing if I change the generate.py"

This reverts commit 7c2b3df6170dcf8d8f36a1de9fcbc9dccdec81f8.

* ignore gitignore

* Delete .gitignore

* Update .gitignore

* Update .gitignore

* Update logic, added multiplicative categories

* Changed difficulties

* Update offline mode so that it works again

* Adjusted difficulty

* New version of the apworld, with 1000 as final score, always

Will still need to check difficulty and weights of adding items.
Website is not ready yet, so this version is not usable yet :)

* Changed yaml and small bug fixes

Fix when goal and max are same
Options: changed chance to weight

* no changes, just whitespaces

* changed how logic works

Now you put an array of mults and the cpu gets a couple of tries

* Changed logic, tweaked a bit too

* Preparation for 2.0

* logic tweak

* Logic for alt categories properly now

* Update setup_en.md

* Update en_YachtDice.md

* Improve performance of add_distributions

* Formatting style

* restore gitignore to APMW

* Tweaked generation parameters and methods

* Version 2.0.3

manual input option
max score in logic always 2.0.3
faster gen

* Comments and editing

* Renamed setup guide

* Improved create_items code

* init of locations: remove self.event line

* Moved setting early items to generate_early

* Add my name to CODEOWNERS

* Added Yacht Dice to the readme in list of games

* Improve performance of Yacht Dice

* newline

* Improve typing

* This is actually just slower lol

* Update worlds/yachtdice/Items.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update Options.py

* Styling

* finished text whichstory option

* removed roll and rollfragments; not used

* import; worlds not world :)

* Option groups!

* ruff styling, fix

* ruff format styling!

* styling and capitalization of options

* small comment

* Cleaned up the "state_is_a_list" a little bit

* RUFF 🐶

* Changed filling the itempool for efficiency

Now, we start with 17 extra items in the item pool, it's quite likely you need at least 17 items (~80%?).
And then afterwards, we delete items if we overshoot the target of 1000, and add items if we haven't reached an achievable score of 1000 yet. Also, no need to recompute the entire logic when adding points.

* 🐶

* Removed plando "fix"

* Changed indent of score multiplier

* faster location function

* Comments to docstrings

* fixed making location closest to goal_score be goal_score

* options format

* iterate keys and values of a dict together

* small optimization ListState

* faster collection of categories

* return arguments instead of making a list (will 🐶 later)

* Instead of turning it into a tuple, you can just make a tuple literal

* remove .keys()

* change .random and used enumerate

* some readability improvements

* Remove location "0", we don't use that one

* Remove lookup_id_to_name entirely

I for sure don't use it, and as far as I know it's not one of the mandatory functions for AP, these are item_name_to_id and location_name_to_id.

* .append instead of += for single items, percentile function changed

Also an extra comment for location ids.

* remove ) too many

* Removed sorted from category list

* Hash categories (which makes it slower :( )

Maybe I messed up or misunderstood...
I'll revert this right away since it is 2x slower, probably because of sorted instead of sort?

* Revert "Hash categories (which makes it slower :( )"

This reverts commit 34f2c1aed8c8813b2d9c58896650b82a810d3578.

* temporary push: 40% faster generation test

Small changes in logic make the generation 40% faster.
I'll have to think about how big the changes are. I suspect they are rather limited.
If this is the way to go, I'll remove the temp file and redo the YachtWeights file, I'll remove the functions there and just put the new weights here.

* Add Points item category

* Reverse changes of bad idea :)

* ruff 🐶

* Use numpy and pmf function to speed up gen

Numpy has a built-in way to sum probability mass functions (pmf).
This shaves of 60% of the generation time :D

* Revert "Use numpy and pmf function to speed up gen"

This reverts commit 9290191cb323ae92321d6c2cfcfe8c27370f439b.

* Step inbetween to change the weights

* Changed the weights to make it faster

135 -> 81 seconds on 100 random yamls

* Adjusted max_dist, split dice_simulation function

* Removed nonlocal and pass arguments instead

* Change "weight-lists" to Dict[str, float]

* Removed the return from ini_locations.

Also added explanations to cat_weights

* Choice options; dont'use .value (will ruff later)

* Only put important options in slotdata

* 🐶

* Add Dict import

* Split the cache per player, limit size to 400.

* 🐶

* added , because of style

* Update apworld version to 2.0.6

2.0.5 is the apworld I released on github to be tested
I never separately released 2.0.4.

* Multiple smaller code improvements

- changed names in YachtWeights so we don't need to translate them in Rules anymore
- we now remember which categories are present in the game, and also put this in slotdata. This we do because only one of two categories is present in a game. If for some reason both are present (plando/getitem/startinventory), we now know which category to ignore
-

* 🐶 ruff

* Mostly minimize_extra_items improvements

- Change logic, generation is now even faster (0.6s per default yaml).
- Made the option 'minimize_extra_items' do a lot more, hopefully this makes the impact of Yacht Dice a little bit less, if you want that. Here's what is also does now:
 - you start with 2 dice and 2 rolls
 - there will be less locations/items at the start of you game

* ruff 🐶

* Removed printing options

* Reworded some option descriptions

* Yacht Dice: setup: change release-link to latest

On the installation page, link to the latest release, instead of the page with all releases

* Several fixes and changes

-change apworld version
-Removed the extra roll (this was not intended)
-change extra_points_added to a mutable list to that it actually does something
-removed variables multipliers_added and items_added
-Rules, don't order by quantity, just by mean_score
-Changed the weights in general to make it faster

* 🐶

* Revert setup to what it was (latest, without S)

* remove temp weights file, shouldn't be here

* Made sure that there is not too many step score multipliers.

Too many step score multipliers lead to gen fails too, probably because you need many categories for them to actually help a lot. So it's hard to use them at the start of the game.

* add filler item name

* Textual fixes and changes

* Remove Victory item and use event instead.

* Revert "Remove Victory item and use event instead."

This reverts commit c2f7d674d392a3acbc1db8614411164ba3b28bff.

* Revert "Textual fixes and changes"

This reverts commit e9432f92454979fcd5a31f8517586585362a7ab7.

* Remove Victory item and make it an event instead

* Yacht Dice logic fix, no decreasing score when obtain item

take 2

* Logic fix: Revert max_tries and mults, change ordering

* Remove spaces :^)

* Updated weights that are stochastically ordered by dice/roll

In the trimming of the weights, sometimes it having 4 rolls would be better than having 5 rolls.
I did a check that this does not happen for any dice increment or roll increment

* Swap for-loops to increase performance

This method is faster if the first for-loop contains fewer items.
Since the function is called with, typically, `dist2` having less items, let's loop over `dist2` first. This makes the entire program 10% faster.

* Remove options with 0 chance from list

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-10-22 21:07:44 +02:00
black-sliver f709d61d04
WebHost: optimize header-logo.svg (#4073)
* WebHost: reduce precision and optimize header-logo.svg

technically those files will not produce an identical output when rendered
however the difference is virtually impossible to see even when rendered to w=4096

* WebHost: keep original svg
2024-10-20 19:52:04 -04:00
black-sliver c6d2971d67
WebHost: optimize WebHost theme PNGs (#4071)
using zopfli, saving 30%
2024-10-20 19:51:14 -04:00
Spineraks af14045c3a
Yacht Dice: Proguseful items: Dice and 100 Points #4070 2024-10-19 16:53:02 +02:00
Remy Jette ede59ef5a1
WebHost: Fix NamedRange option dropdown being blank instead of custom when applying presets (#4063) 2024-10-17 18:40:46 +02:00
Bryce Wilson 63d471514f
Pokemon Emerald: Add flag for shoal cave to bounces (#4021)
* Pokemon Emerald: Add shoal cave state to map updates

* Pokemon Emerald: Fix shoal cave flag wrong byte, delay bounce to end of map transition
2024-10-17 03:37:41 +02:00
palex00 ff297f2951
[Aquaria] Adds Poptracker Pack to the Aquaria Setup Guides (#4037)
* Adds Poptracker Pack to the Aquaria Setup Guides

* Updates French Update Guide

* Update worlds/aquaria/docs/setup_fr.md

Co-authored-by: Cipocreep <65617616+Cipocreep@users.noreply.github.com>

* Update worlds/aquaria/docs/setup_fr.md

Co-authored-by: Benny D <78334662+benny-dreamly@users.noreply.github.com>

* Update setup_fr.md

* Update setup_fr.md

---------

Co-authored-by: Cipocreep <65617616+Cipocreep@users.noreply.github.com>
Co-authored-by: Benny D <78334662+benny-dreamly@users.noreply.github.com>
2024-10-17 03:34:10 +02:00
Scipio Wright a0f49dd7d9
Noita: Add the useful classification to important perks, making them progression + useful #4030 2024-10-17 03:31:53 +02:00
qwint 79cec89e24
Launcher: save default settings before opening file for users (#4042) 2024-10-17 00:27:50 +02:00
Ishigh1 2b0cab82fa
CommonClient: Making local datapackage load correctly if it was overriden by a custom one (#3722)
* Added versions and checksums dict

* Added load of local datapackage

* Fixed typo
2024-10-17 00:14:27 +02:00
Fabian Dill 48822227b5
Test: option instances have to be pickleable (#4006) 2024-10-16 23:31:36 +02:00
Fabian Dill 375b5796d9
WebHost: noscript faq and glossary (#4061) 2024-10-16 23:28:42 +02:00
Jarno c12ed316cf
Timespinner: Make hidden options pickleables (#4050)
* Make timespinner hidden options pickleables

* Keep changes minimal

* Change line endings
2024-10-16 23:06:14 +02:00
Bryce Wilson 26577b16dc
Pokemon Emerald: Fix opponent blacklist checking wrong option (#4058) 2024-10-15 23:28:36 +02:00
Louis M af0b5f8cf2
Aquaria Fixing some bugs (#4057)
* Fixing some bugs

* Forgot about this one
2024-10-15 23:22:58 +02:00
Louis M 618564c60a
Aquaria: Adding slot data for poptracker (#4056)
* Adds neccessary slot data for Aquaria

* Comma oops

---------

Co-authored-by: palex00 <32203971+palex00@users.noreply.github.com>
2024-10-14 18:53:20 +02:00
Seafo f2ac937d1e
Minecraft: Fix plando connections #4048
Plando connections was broken as a result of https://github.com/ArchipelagoMW/Archipelago/pull/3765
This fixes it.
2024-10-14 00:22:37 +02:00
Scipio Wright d4d777b101
OoT: Add aliases for Progressive Hookshot (#4052)
* Add aliases for Progressive Hookshot

* Update worlds/oot/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-10-14 00:17:53 +02:00
Fabian Dill b772d42df5
Core: turn MultiServer item_names and location_names into instance vars (#4053) 2024-10-14 00:15:53 +02:00
Exempt-Medic e8f3aa96da
Timespinner: Two typos #4051 2024-10-13 23:21:36 +02:00
gurglemurgle5 2d0bdebaa9
Docs: Add ConnectUpdate to the list of client packets in the network protocol documentation #4045 2024-10-13 02:01:28 +02:00
Fabian Dill ef4d1e77e3
Core: make shlex split an attempt with regular split retry (#4046) 2024-10-11 23:24:42 +02:00
Aaron Wagener f495bf7261
The Messenger: fix missing money wrench rule (#4041)
* The Messenger: fix missing money wrench rule

* add a unit test for money wrench
2024-10-11 03:05:21 +02:00
Exempt-Medic 2751ccdaab
DS3: Make your own region cache (#4040)
* Make your own region cache

* Using a string
2024-10-11 03:02:31 +02:00
black-sliver 6287bc27a6
WebHost: Fix too-many-players error not showing (#4033)
* WebHost: fix 'too many players' error not showing

* WebHost, Tests: add basic tests for generate endpoint

* WebHost: hopefully make CodeQL happy with MAX_ROLL redirect
2024-10-05 18:14:22 +02:00
palex00 97f2c25924
[KH2] Adds more options to slot data #4031 2024-10-05 02:13:04 +02:00
Bryce Wilson e5a0ef799f
Pokemon Emerald: Update changelog (#4003) 2024-10-04 21:28:43 +02:00
Silvris 216e0603e1
KDL3: Fix webhost not giving a patch #4023 2024-10-04 21:27:23 +02:00
Fabian Dill 05a67386c6
Core: use shlex splitting instead of whitespace splitting for client and server commands (#4011) 2024-10-02 03:09:43 +02:00
NewSoupVi 0ec9039ca6
The Witness: Small code refactor (cast_not_none) (#3798)
* cast not none

* ruff

* Missed a spot
2024-10-02 00:02:17 +02:00
Aaron Wagener f06f95d03d
Core: move race_mode to read_data instead of stored_data (#4020)
* move race_mode to read_data

* add race_mode to docs
2024-10-01 23:55:34 +02:00
Mysteryem 5a853dfccd
Tests: Fix indentation in TestTwoPlayerMulti (#4010)
The "filling multiworld" subtest was at the wrong indentation, so was
only running for the last world_type.

"games" has additionally been added to the subtest to help better
identify failures.

Now that the subtest is actually being run for each world type, this
adds about 20 seconds to the duration of the test on my machine.
2024-10-01 21:30:45 +02:00
Alex Nordstrom 23469fa5c3
LADX: ghost fills ammo to initial max (#4005)
* ghost fills ammo to max

* Revert "ghost fills ammo to max"

This reverts commit 68804fef1403197f2192e4c7d02f8793ac1c7ca0.

* fill to first max
2024-10-01 21:09:23 +02:00
Bryce Wilson dc1da4e88b
Pokemon Emerald: Another wonder trade fix (#4014)
* Pokemon Emerald: Another guarded write on wonder trades

* Pokemon Emerald: Reorder sending wonder trade and erasing data

In case the guarded write fails
2024-10-01 21:08:43 +02:00
Aaron Wagener 67f6b458d7
Core: add race mode to multidata and datastore (#4017)
* add race mode to multidata and datastore

* have commonclient check race mode on connect and add it to the tooltip ui
2024-10-01 21:08:13 +02:00
Bryce Wilson 8193fa12b2
BizHawkClient: Fix typing mistake (#3938) 2024-09-28 22:49:11 +02:00
Fabian Dill de0c498470
Core: update World method comment (#3866) 2024-09-28 22:37:42 +02:00
qwint 7337309426
CommonClient: add more docstrings and comments #3821 2024-09-27 01:34:54 +02:00
Natalie Weizenbaum 3205e9b3a0
DS3: Update setup instructions (#3817)
* DS3: Point the DS3 client link to my GitHub

It's not clear if/when my PR will land for the upstream fork, or if we'll just start using my fork as the primary source of truth. For now, it's the only one with 3.0.0-compatible releases.

* DS3: Document Proton support

* DS3: Document another way to get a YAML template

* DS3: Don't say that the mod will force offline mode

ModEngine2 is *supposed to* do this, but in practice it does not

* Code review

* Update Linux instructions per user experiences
2024-09-27 01:31:50 +02:00
palex00 05439012dc
Adjusts Whitespaces in the Plando Doc to be able to be copied directly (#3902)
* Update plando_en.md

* Also adjusts plando_connections indentation

* ughh
2024-09-27 01:30:23 +02:00
soopercool101 177c0fef52
SM64: Remove outdated information on save bugs from setup guide (#3879)
* Remove outdated information from SM64 setup guide

Recent build changes have made it so that old saves no longer remove logical gates or prevent Toads from granting stars, remove info highlighting these issues.

* Better line break location
2024-09-27 01:29:26 +02:00
BadMagic100 5c4e81d046
Hollow Knight: Clean outdated slot data code and comments #3988 2024-09-27 01:27:22 +02:00
agilbert1412 a2d585ba5c
Stardew Valley: Add Cinder Shard resource pack (#4001)
* - Add Cinder Shard resource pack

* - Make it ginger island exclusive
2024-09-27 01:26:06 +02:00
Aaron Wagener 5ea55d77b0
The Messenger: add webhost auto connection steps to guide (#3904)
* The Messenger: add webhost auto connection steps to guide and fix doc spacing

* rever comments

* add notes about potential steam popup

* medic's feedback

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-09-27 01:25:41 +02:00
Ziktofel ab8caea8be
SC2: Fix item origins, so including/excluding NCO/BW/EXT items works properly (#3990) 2024-09-27 00:57:21 +02:00
Benny D a043ed50a6
Timespinner: Fix Typo in Download Location #3997 2024-09-27 00:56:36 +02:00
qwint e85a835b47
Core: use base collect/remove for item link groups (#3999)
* use base collect/remove for item link groups

* Update BaseClasses.py

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-09-27 00:02:10 +02:00
Felix R 9a9fea0ca2
bumpstik: add hazard bumpers to completion (#3991)
* bumpstik: add hazard bumpers to completion

* bumpstik: update to use has_all_counts for completion
as suggested by ScipioWright
2024-09-26 20:47:03 +02:00
NewSoupVi e910a37273
Core: Put an assert for parent region in Entrance.can_reach just like the one in Location.can_reach (#3998)
* Core: Move connection.parent_region assert to can_reach

This is how it already works for locations and it feels more correct to me to check in the place where the crash would happen.

Also update location error to be a bit more verbose

* Bring back the other assert

* Update BaseClasses.py
2024-09-25 17:47:38 +02:00
Kory Dondzila f06d4503d8
Adds link to other players' trackers in player hints. (#3569) 2024-09-23 17:21:03 -04:00
Mrks 8021b457b6
WebHost: Added Games Of A Seed To The User Content Page (#3585)
* Added contained games of a seed to the user content page as tooltip.

* Changed sort handling.

* Limited amount of shown games.

* Added missing dashes.

Co-authored-by: Kory Dondzila <kory.dondzila@atomicobject.com>

* Closing a-tags.

Co-authored-by: Kory Dondzila <kory.dondzila@atomicobject.com>

* Closing a-tags.

Co-authored-by: Kory Dondzila <kory.dondzila@atomicobject.com>

* Moved games list to table cell level.

Co-authored-by: Kory Dondzila <kory.dondzila@atomicobject.com>

* Moved games list to table cell level.

---------

Co-authored-by: Kory Dondzila <kory.dondzila@atomicobject.com>
2024-09-23 17:19:26 -04:00
agilbert1412 d43dc62485
Stardew Valley: Improve Junimo Kart Regions #3984 2024-09-23 00:14:04 +02:00
Silvris f7ec3d7508
kvui: abstract away client tab additions #3950 2024-09-22 16:24:14 +02:00
CookieCat 99c02a3eb3
AHIT: Fix Death Wish option check typo (#3978)
* duh

* Fuck it

* Major fixes

* a

* b

* Even more fixes

* New option - NoFreeRoamFinale

* a

* Hat Logic Fix

* Just to be safe

* multiworld.random to world.random

* KeyError fix

* Update .gitignore

* Update __init__.py

* Zoinks Scoob

* ffs

* Ruh Roh Raggy, more r-r-r-random bugs!

* 0.9b - cleanup + expanded logic difficulty

* Update Rules.py

* Update Regions.py

* AttributeError fix

* 0.10b - New Options

* 1.0 Preparations

* Docs

* Docs 2

* Fixes

* Update __init__.py

* Fixes

* variable capture my beloathed

* Fixes

* a

* 10 Seconds logic fix

* 1.1

* 1.2

* a

* New client

* More client changes

* 1.3

* Final touch-ups for 1.3

* 1.3.1

* 1.3.3

* Zero Jumps gen error fix

* more fixes

* Formatting improvements

* typo

* Update __init__.py

* Revert "Update __init__.py"

This reverts commit e178a7c0a6904ace803241cab3021d7b97177e90.

* init

* Update to new options API

* Missed some

* Snatcher Coins fix

* Missed some more

* some slight touch ups

* rewind

* a

* fix things

* Revert "Merge branch 'main' of https://github.com/CookieCat45/Archipelago-ahit"

This reverts commit a2360fe197e77a723bb70006c5eb5725c7ed3826, reversing
changes made to b8948bc4958855c6e342e18bdb8dc81cfcf09455.

* Update .gitignore

* 1.3.6

* Final touch-ups

* Fix client and leftover old options api

* Delete setup-ahitclient.py

* Update .gitignore

* old python version fix

* proper warnings for invalid act plandos

* Update worlds/ahit/docs/en_A Hat in Time.md

Co-authored-by: Danaël V. <104455676+ReverM@users.noreply.github.com>

* Update worlds/ahit/docs/setup_en.md

Co-authored-by: Danaël V. <104455676+ReverM@users.noreply.github.com>

* 120 char per line

* "settings" to "options"

* Update DeathWishRules.py

* Update worlds/ahit/docs/en_A Hat in Time.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* No more loading the data package

* cleanup + act plando fixes

* almost forgot

* Update Rules.py

* a

* Update worlds/ahit/Options.py

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* Options stuff

* oop

* no unnecessary type hints

* warn about depot download length in setup guide

* Update worlds/ahit/Options.py

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* typo

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* Update worlds/ahit/Rules.py

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* review stuff

* More stuff from review

* comment

* 1.5 Update

* link fix?

* link fix 2

* Update setup_en.md

* Update setup_en.md

* Update setup_en.md

* Evil

* Good fucking lord

* Review stuff again + Logic fixes

* More review stuff

* Even more review stuff - we're almost done

* DW review stuff

* Finish up review stuff

* remove leftover stuff

* a

* assert item

* add A Hat in Time to readme/codeowners files

* Fix range options not being corrected properly

* 120 chars per line in docs

* Update worlds/ahit/Regions.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* Update worlds/ahit/DeathWishLocations.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* Remove some unnecessary option.class.value

* Remove data_version and more option.class.value

* Update worlds/ahit/Items.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* Remove the rest of option.class.value

* Update worlds/ahit/DeathWishLocations.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* review stuff

* Replace connect_regions with Region.connect

* review stuff

* Remove unnecessary Optional from LocData

* Remove HatType.NONE

* Update worlds/ahit/test/TestActs.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* fix so default tests actually don't run

* Improve performance for death wish rules

* rename test file

* change test imports

* 1000 is probably unnecessary

* a

* change state.count to state.has

* stuff

* starting inventory hats fix

* shouldn't have done this lol

* make ship shape task goal equal to number of tasksanity checks if set to 0

* a

* change act shuffle starting acts + logic updates

* dumb

* option groups + lambda capture cringe + typo

* a

* b

* missing option in groups

* c

* Fix Your Contract Has Expired being placed on first level when it shouldn't

* yche fix

* formatting

* major logic bug fix for death wish

* Update Regions.py

* Add missing indirect connections

* Fix generation error from chapter 2 start with act shuffle off

* a

* Revert "a"

This reverts commit df58bbcd998585760cc6ac9ea54b6fdf142b4fd1.

* Revert "Fix generation error from chapter 2 start with act shuffle off"

This reverts commit 0f4d441824af34bf7a7cff19f5f14161752d8661.

* Fix option typo

* I lied, it's actually two lines

---------

Co-authored-by: Danaël V. <104455676+ReverM@users.noreply.github.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
Co-authored-by: Ixrec <ericrhitchcock@gmail.com>
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2024-09-22 16:22:11 +02:00
Scipio Wright 449782a4d8
TUNIC: Add forgotten Laurels rule for Beneath the Vault Boxes #3981 2024-09-22 16:21:10 +02:00
CookieCat 97ca2ad258
AHIT: Fix massive lag spikes in extremely large multiworlds, add extra security to prevent loading the wrong save file for a seed (#3718)
* duh

* Fuck it

* Major fixes

* a

* b

* Even more fixes

* New option - NoFreeRoamFinale

* a

* Hat Logic Fix

* Just to be safe

* multiworld.random to world.random

* KeyError fix

* Update .gitignore

* Update __init__.py

* Zoinks Scoob

* ffs

* Ruh Roh Raggy, more r-r-r-random bugs!

* 0.9b - cleanup + expanded logic difficulty

* Update Rules.py

* Update Regions.py

* AttributeError fix

* 0.10b - New Options

* 1.0 Preparations

* Docs

* Docs 2

* Fixes

* Update __init__.py

* Fixes

* variable capture my beloathed

* Fixes

* a

* 10 Seconds logic fix

* 1.1

* 1.2

* a

* New client

* More client changes

* 1.3

* Final touch-ups for 1.3

* 1.3.1

* 1.3.3

* Zero Jumps gen error fix

* more fixes

* Formatting improvements

* typo

* Update __init__.py

* Revert "Update __init__.py"

This reverts commit e178a7c0a6904ace803241cab3021d7b97177e90.

* init

* Update to new options API

* Missed some

* Snatcher Coins fix

* Missed some more

* some slight touch ups

* rewind

* a

* fix things

* Revert "Merge branch 'main' of https://github.com/CookieCat45/Archipelago-ahit"

This reverts commit a2360fe197e77a723bb70006c5eb5725c7ed3826, reversing
changes made to b8948bc4958855c6e342e18bdb8dc81cfcf09455.

* Update .gitignore

* 1.3.6

* Final touch-ups

* Fix client and leftover old options api

* Delete setup-ahitclient.py

* Update .gitignore

* old python version fix

* proper warnings for invalid act plandos

* Update worlds/ahit/docs/en_A Hat in Time.md

Co-authored-by: Danaël V. <104455676+ReverM@users.noreply.github.com>

* Update worlds/ahit/docs/setup_en.md

Co-authored-by: Danaël V. <104455676+ReverM@users.noreply.github.com>

* 120 char per line

* "settings" to "options"

* Update DeathWishRules.py

* Update worlds/ahit/docs/en_A Hat in Time.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* No more loading the data package

* cleanup + act plando fixes

* almost forgot

* Update Rules.py

* a

* Update worlds/ahit/Options.py

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* Options stuff

* oop

* no unnecessary type hints

* warn about depot download length in setup guide

* Update worlds/ahit/Options.py

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* typo

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* Update worlds/ahit/Rules.py

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* review stuff

* More stuff from review

* comment

* 1.5 Update

* link fix?

* link fix 2

* Update setup_en.md

* Update setup_en.md

* Update setup_en.md

* Evil

* Good fucking lord

* Review stuff again + Logic fixes

* More review stuff

* Even more review stuff - we're almost done

* DW review stuff

* Finish up review stuff

* remove leftover stuff

* a

* assert item

* add A Hat in Time to readme/codeowners files

* Fix range options not being corrected properly

* 120 chars per line in docs

* Update worlds/ahit/Regions.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* Update worlds/ahit/DeathWishLocations.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* Remove some unnecessary option.class.value

* Remove data_version and more option.class.value

* Update worlds/ahit/Items.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* Remove the rest of option.class.value

* Update worlds/ahit/DeathWishLocations.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* review stuff

* Replace connect_regions with Region.connect

* review stuff

* Remove unnecessary Optional from LocData

* Remove HatType.NONE

* Update worlds/ahit/test/TestActs.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* fix so default tests actually don't run

* Improve performance for death wish rules

* rename test file

* change test imports

* 1000 is probably unnecessary

* a

* change state.count to state.has

* stuff

* starting inventory hats fix

* shouldn't have done this lol

* make ship shape task goal equal to number of tasksanity checks if set to 0

* a

* change act shuffle starting acts + logic updates

* dumb

* option groups + lambda capture cringe + typo

* a

* b

* missing option in groups

* c

* Fix Your Contract Has Expired being placed on first level when it shouldn't

* yche fix

* formatting

* major logic bug fix for death wish

* Update Regions.py

* Add missing indirect connections

* Fix generation error from chapter 2 start with act shuffle off

* a

* Revert "a"

This reverts commit df58bbcd998585760cc6ac9ea54b6fdf142b4fd1.

* Revert "Fix generation error from chapter 2 start with act shuffle off"

This reverts commit 0f4d441824af34bf7a7cff19f5f14161752d8661.

* fix async lag

* Update Client.py

* shop item names need this now

* fix indentation

---------

Co-authored-by: Danaël V. <104455676+ReverM@users.noreply.github.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
Co-authored-by: Ixrec <ericrhitchcock@gmail.com>
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2024-09-21 23:10:18 +02:00
Kaito Sinclaire 2b88be5791
Doom 1993 (auto-generated files): Update E4 logic (#3957) 2024-09-21 23:06:31 +02:00
agilbert1412 204e940f47
Stardew Valley: Fix Art Of Crabbing Logic and Extract Festival Logic (#3625)
* here you go kaito kid

* here you go kaito kid

* move reward logic in its own method

---------

Co-authored-by: Jouramie <jouramie@hotmail.com>
Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>
2024-09-21 23:05:00 +02:00
Scipio Wright 69d3db21df
TUNIC: Deal with the boxes blocking the entrance to Beneath the Vault 2024-09-21 23:02:58 +02:00
qwint 41ddb96b24
HK: add race bool to slot data (#3971) 2024-09-21 16:45:22 +02:00
João Victor ba8f03516e
Docs: added Brazilian Portuguese Translation for Hollow Knight setup guide (#3909)
* add neww pt-br translation

* setup file

* Update setup_pt_br.md

* add ` to paths

* correct grammar

* add space .-.

* add more spaces .-. .-. .-.

* capitalize HK

* Update setup_pt_br.md

* accent not the same as punctuation

* small changes

* Update setup_pt_br.md
2024-09-20 19:19:48 +02:00
Spineraks 0095eecf2b
Yacht Dice: Remove Victory item and make it an event instead (#3968)
* Add the yacht dice (from other git) world to the yacht dice fork

* Update .gitignore

* Removed zillion because it doesn't work

* Update .gitignore

* added zillion again...

* Now you can have 0 extra fragments

* Added alt categories, also options

* Added item categories

* Extra categories are now working! 🐶

* changed options and added exceptions

* Testing if I change the generate.py

* Revert "Testing if I change the generate.py"

This reverts commit 7c2b3df6170dcf8d8f36a1de9fcbc9dccdec81f8.

* ignore gitignore

* Delete .gitignore

* Update .gitignore

* Update .gitignore

* Update logic, added multiplicative categories

* Changed difficulties

* Update offline mode so that it works again

* Adjusted difficulty

* New version of the apworld, with 1000 as final score, always

Will still need to check difficulty and weights of adding items.
Website is not ready yet, so this version is not usable yet :)

* Changed yaml and small bug fixes

Fix when goal and max are same
Options: changed chance to weight

* no changes, just whitespaces

* changed how logic works

Now you put an array of mults and the cpu gets a couple of tries

* Changed logic, tweaked a bit too

* Preparation for 2.0

* logic tweak

* Logic for alt categories properly now

* Update setup_en.md

* Update en_YachtDice.md

* Improve performance of add_distributions

* Formatting style

* restore gitignore to APMW

* Tweaked generation parameters and methods

* Version 2.0.3

manual input option
max score in logic always 2.0.3
faster gen

* Comments and editing

* Renamed setup guide

* Improved create_items code

* init of locations: remove self.event line

* Moved setting early items to generate_early

* Add my name to CODEOWNERS

* Added Yacht Dice to the readme in list of games

* Improve performance of Yacht Dice

* newline

* Improve typing

* This is actually just slower lol

* Update worlds/yachtdice/Items.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update Options.py

* Styling

* finished text whichstory option

* removed roll and rollfragments; not used

* import; worlds not world :)

* Option groups!

* ruff styling, fix

* ruff format styling!

* styling and capitalization of options

* small comment

* Cleaned up the "state_is_a_list" a little bit

* RUFF 🐶

* Changed filling the itempool for efficiency

Now, we start with 17 extra items in the item pool, it's quite likely you need at least 17 items (~80%?).
And then afterwards, we delete items if we overshoot the target of 1000, and add items if we haven't reached an achievable score of 1000 yet. Also, no need to recompute the entire logic when adding points.

* 🐶

* Removed plando "fix"

* Changed indent of score multiplier

* faster location function

* Comments to docstrings

* fixed making location closest to goal_score be goal_score

* options format

* iterate keys and values of a dict together

* small optimization ListState

* faster collection of categories

* return arguments instead of making a list (will 🐶 later)

* Instead of turning it into a tuple, you can just make a tuple literal

* remove .keys()

* change .random and used enumerate

* some readability improvements

* Remove location "0", we don't use that one

* Remove lookup_id_to_name entirely

I for sure don't use it, and as far as I know it's not one of the mandatory functions for AP, these are item_name_to_id and location_name_to_id.

* .append instead of += for single items, percentile function changed

Also an extra comment for location ids.

* remove ) too many

* Removed sorted from category list

* Hash categories (which makes it slower :( )

Maybe I messed up or misunderstood...
I'll revert this right away since it is 2x slower, probably because of sorted instead of sort?

* Revert "Hash categories (which makes it slower :( )"

This reverts commit 34f2c1aed8c8813b2d9c58896650b82a810d3578.

* temporary push: 40% faster generation test

Small changes in logic make the generation 40% faster.
I'll have to think about how big the changes are. I suspect they are rather limited.
If this is the way to go, I'll remove the temp file and redo the YachtWeights file, I'll remove the functions there and just put the new weights here.

* Add Points item category

* Reverse changes of bad idea :)

* ruff 🐶

* Use numpy and pmf function to speed up gen

Numpy has a built-in way to sum probability mass functions (pmf).
This shaves of 60% of the generation time :D

* Revert "Use numpy and pmf function to speed up gen"

This reverts commit 9290191cb323ae92321d6c2cfcfe8c27370f439b.

* Step inbetween to change the weights

* Changed the weights to make it faster

135 -> 81 seconds on 100 random yamls

* Adjusted max_dist, split dice_simulation function

* Removed nonlocal and pass arguments instead

* Change "weight-lists" to Dict[str, float]

* Removed the return from ini_locations.

Also added explanations to cat_weights

* Choice options; dont'use .value (will ruff later)

* Only put important options in slotdata

* 🐶

* Add Dict import

* Split the cache per player, limit size to 400.

* 🐶

* added , because of style

* Update apworld version to 2.0.6

2.0.5 is the apworld I released on github to be tested
I never separately released 2.0.4.

* Multiple smaller code improvements

- changed names in YachtWeights so we don't need to translate them in Rules anymore
- we now remember which categories are present in the game, and also put this in slotdata. This we do because only one of two categories is present in a game. If for some reason both are present (plando/getitem/startinventory), we now know which category to ignore
-

* 🐶 ruff

* Mostly minimize_extra_items improvements

- Change logic, generation is now even faster (0.6s per default yaml).
- Made the option 'minimize_extra_items' do a lot more, hopefully this makes the impact of Yacht Dice a little bit less, if you want that. Here's what is also does now:
 - you start with 2 dice and 2 rolls
 - there will be less locations/items at the start of you game

* ruff 🐶

* Removed printing options

* Reworded some option descriptions

* Yacht Dice: setup: change release-link to latest

On the installation page, link to the latest release, instead of the page with all releases

* Several fixes and changes

-change apworld version
-Removed the extra roll (this was not intended)
-change extra_points_added to a mutable list to that it actually does something
-removed variables multipliers_added and items_added
-Rules, don't order by quantity, just by mean_score
-Changed the weights in general to make it faster

* 🐶

* Revert setup to what it was (latest, without S)

* remove temp weights file, shouldn't be here

* Made sure that there is not too many step score multipliers.

Too many step score multipliers lead to gen fails too, probably because you need many categories for them to actually help a lot. So it's hard to use them at the start of the game.

* add filler item name

* Textual fixes and changes

* Remove Victory item and use event instead.

* Revert "Remove Victory item and use event instead."

This reverts commit c2f7d674d392a3acbc1db8614411164ba3b28bff.

* Revert "Textual fixes and changes"

This reverts commit e9432f92454979fcd5a31f8517586585362a7ab7.

* Remove Victory item and make it an event instead

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-09-20 19:07:45 +02:00
Alex Nordstrom 79942c09c2
LADX: define filler item, fix for extra golden leaves (#3918)
* set filler item
also rename "Master Stalfos' Message" to "Nothing" as it shows up in game, and "Gel" to "Zol Attack"

* fix for extra gold leaves

* fix for start_inventory
2024-09-20 16:18:09 +02:00
digiholic 1b15c6920d
[OSRS] Adds display names to Options #3954 2024-09-20 16:15:30 +02:00
gaithern 499d79f089
Kingdom Hearts: Fix Hint Spam and Add Setting Queries #3899 2024-09-19 22:32:47 +02:00
NewSoupVi 926e08513c
The Witness: Remove some unused code #3852 2024-09-19 01:57:59 +02:00
Silvris 025c550991
Ocarina of Time: options and general cleanup (#3767)
* working?

* missed one

* fix old start inventory usage

* missed global random usage

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-09-18 21:26:59 +02:00
Doug Hoskisson fced9050a4
Zillion: fix logic cache (#3719) 2024-09-18 21:09:47 +02:00
Faris 2ee8b7535d
OSRS: UT integration for OSRS to support chunksanity (#3776) 2024-09-18 20:53:17 +02:00
Remy Jette 0d35cd4679
BizHawkClient: Avoid error launching BizHawkClient via Launcher CLI (#3554)
* Core, BizHawkClient: Support launching BizHawkClient via Launcher command line

* Revert changes to LauncherComponents.py
2024-09-18 20:42:22 +02:00
Alchav db5d9fbf70
Pokemon R/B: Version 5 Update (#3566)
* Quiz updates

* Enable Partial Trainersanity

* Losable Key Items Still Count

* New options api

* Type Chart Seed

* Continue switching to new options API

* Level Scaling and Quiz fixes

* Level Scaling and Quiz fixes

* Clarify that palettes are only for Super Gameboy

* Type chart seed groups use one random players' options

* remove goal option again

* Text updates

* Trainersanity Trainers ignore Blind Trainers setting

* Re-order simple connecting interiors so that directions are preserved when possible

* Dexsanity exact number

* Year update

* Dexsanity Doc update

* revert accidental file deletion

* Fixes

* Add world parameter to logic calls

* restore correct seeded random object

* missing world.options changes

* Trainersanity table bug fix

* delete entrances as well as exits when restarting door shuffle

* Do not collect route 25 item for level scaling if trainer is trainersanity

* world.options in level_scaling.py

* Update worlds/pokemon_rb/level_scaling.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/pokemon_rb/encounters.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/pokemon_rb/encounters.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* world -> multiworld

* Fix Cerulean Cave Hidden Item Center Rocks region

* Fix Cerulean Cave Hidden Item Center Rocks region for real

* Remove "self-locking" rules

* Update worlds/pokemon_rb/regions.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Fossil events

* Update worlds/pokemon_rb/level_scaling.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: alchav <alchav@jalchavware.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-09-18 20:37:17 +02:00
jamesbrq 51a6dc150c
MLSS: Various bugfixes and QoL updates (#3744)
* Small fixes

* Update Location names + Remove redundant rule

* Fix for str not being returned in get_filler_item_name()

* ASM changes + various name/logic updates

* Remove extra unintended change + Make beanstone/beanlets useful

* Add missing timer logic to client

* Update Rules.py

* Fix bad capitalization

* Small formatting and ASM changes

* Update basepatch.bsdiff

* Update seed verification to be more likely to make a correct comparison

* Add Pipe 10

* Final batch of small fixes

* FINAL CHANGE I SWEAR

* Added victory Item for spoilers

* Update worlds/mlss/Regions.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/Items.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Fix jokes end logic

* Update worlds/mlss/Regions.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Fix jokes end logic

* Item Location mismatch + Check options against rules

* Change List to Set + Check options against rules

* Moved Victory item to event

* Update worlds/mlss/__init__.py

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>

* Update worlds/mlss/__init__.py

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-09-18 19:33:02 +02:00
black-sliver 710609fa60
WebHost: move api/room_status out of __init__.py (#3958)
* WebHost: move room_status out of __init__.py

The old location is unexpected and easy to miss.

* WebHost: fix typing in api/room_status
2024-09-18 10:27:53 +02:00
Fabian Dill da781bb4ac
Core: rename yaml_output to csv_output (#3955) 2024-09-18 04:37:10 +02:00
Aaron Wagener 69487661dd
Core: change yaml_output to output a full csv (#3653)
* make yaml_output arg a bool instead of number

* make yaml_output dump all player options as csv

* it sorts by game so swap those columns

* capitalize game and name headers

* use a list and just add an if before adding instead of sorting

* skip options that the world doesn't want displayed

* check if the class is a subclass of Removed specifically instead of the none flag

* don't create empty rows

* add a header for every game option that isn't from the common ones even if they have the same name

* add to webhost gen args so it can still gen
2024-09-18 01:33:03 +02:00
black-sliver f73c0d9894
WebHost: Better host room v2 (#3948)
* WebHost: add spinner to room command

and show error message if fetch fails due to NetworkError

* WebHost: don't update room log while tab is inactive

* WebHost: don't include log for automated requests

* WebHost: refresh room also for re-spinups

and do that from javascript

* Test, WebHost: send fake user-agent where required

* WebHost: remove wrong comment in host room
2024-09-18 00:47:26 +02:00
Fabian Dill 6fac83b84c
Factorio: update API use (#3760)
---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-09-18 00:18:17 +02:00
sgrunt debb936618
DOOM II: Fix sector 95 assignment in DOOM II MAP17 to correctly flag the BFG9000 location as in the Yellow Key area (#3705)
Co-authored-by: sgrunt <sgrunt1987@gmail.com>
2024-09-18 00:08:18 +02:00
agilbert1412 8c5b65ff26
Stardew Valley: Remove Accessibility and progression balancing from presets #3833 2024-09-18 00:07:40 +02:00
agilbert1412 a7c96436d9
Stardew valley: Add Marlon bedroom entrance rule (#3735)
* - Created a test for the "Mapping Cave Systems" book

* - Added missing rule to marlon's bedroom

* - Can kill any monster, not just green slime

* - Added a compound source structure, but I ended up deciding to not use it here. Still keeping it as it will probably be useful eventually

* - Use the compound source of the monster compoundium (ironic, I know)

* - Add required elevators

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-09-18 00:03:33 +02:00
Aaron Wagener 4e60f3cc54
The Messenger: Fix Portal Plando Issues (#3838)
* add a more clear error message for a missing exit

* remove portal region from the available pool

* ensure plando portals are in the correct spot in the list and it gets cleared correctly
2024-09-18 00:00:26 +02:00
Exempt-Medic 30a0b337a2
DS3: Make Red Eye Orb always require Lift Chamber Key #3857 2024-09-17 23:58:45 +02:00
Scipio Wright 4ea1dddd2f
TUNIC: Better logic for Library Lab glass and Fortress leaf piles #3880 2024-09-17 23:57:55 +02:00
Mrks dc218b7997
LADX: Adding Slot Data For Magpie Tracker (#3582)
* wip: LADX slot_data

* LADX: slot_data

* Sending slot_data to magpie.

* Moved sending slot_data from pushing to pull by Magpie request.

* Adding EoF newline to tracker.py.

* Update Tracker.py

* Update __init__.py

* Update LinksAwakeningClient.py

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-09-17 23:56:40 +02:00
Natalie Weizenbaum 78c5489189
DS3: Mark the Archdeacon Set as downstream of Deacons of the Deep (#3883)
This ensures that if Deacons is replaced with Yhorm, the Storm Ruler
won't show up in these locations.
2024-09-17 23:50:02 +02:00
Bryce Wilson d1a7bc66e6
Pokemon Emerald: Prevent client from spamming goal status update (#3900) 2024-09-17 23:49:36 +02:00
Ziktofel b982e9ebb4
SC2: Fix /received display bugs (#3949)
* SC2: Fix location display in /received command

* SC2: Backport broken markup fix in /received output from the dev branch

* Cleanup
2024-09-17 23:18:43 +02:00
Bryce Wilson 8f7e0dc441
Core: Improve death link option description (#3951) 2024-09-17 23:17:41 +02:00
Bryce Wilson 5aea8d4ab5
Pokemon Emerald: Update changelog (#3952) 2024-09-17 15:14:05 +02:00
Rensen3 97be5f1dde
YGO06: slotdata fix (#3953)
* YGO06: fix slot data for universal tracker

* YGO06: put Extremely Low Deck Bonus after Low Deck Bonus
2024-09-17 15:13:19 +02:00
Mysteryem dae3fe188d
OOT: Fix incorrect region accessibility after update_reachable_regions() (#3712)
`CollectionState.update_reachable_regions()` un-stales the state for all
players, but when checking `OOTRegion.can_reach()`, it would only update
OOT's age region accessibility when the state was stale, so if the state
was always un-staled by `update_reachable_regions()` immediately before
`OOTRegion.can_reach()`, OOT's age region accessibility would never
update.

This patch fixes the issue by replacing use of CollectionState.stale
with a separate stale state dictionary specific to OOT that is only
un-staled by `_oot_update_age_reachable_regions()`.

OOT's collect() and remove() implementations have been updated to stale
the new OOT-specific state.
2024-09-17 15:11:35 +02:00
Exempt-Medic 96542fb2d8
Blasphemous: Move pre_fill to create_items #3901 2024-09-17 15:08:15 +02:00
qwint ec50b0716a
Core: Add color conversions for colorama/terminal output #3940 2024-09-17 14:44:32 +02:00
Bryce Wilson f8d3c26e3c
Pokemon Emerald: Fix unguarded wonder trade write (#3939) 2024-09-17 14:43:22 +02:00
digiholic 1c0cec0de2
[OSRS] Adds Description to OSRS World #3921 2024-09-17 14:42:48 +02:00
Silvris 4692e6f08a
MM2: fix Air Shooter minimum damage #3922 2024-09-17 14:42:19 +02:00
Mysteryem b8d23ec595
MMBN3: Add missing indirect conditions (#3931)
Entrances to SciLab_Cyberworld and Yoka_Cyberworld had logic for being
able to reach SciLab_Overworld, but did not register this indirect
condition.

Entrances to Beach_Cyberworld had logic for being able to reach
Yoka_Overworld, but did not register this indirect condition.

Entrances to Undernet and Secret_Area had logic for having a high enough
explore score, but explore score is calculated based on the
accessibility of a number of regions and no indirect conditions were
being registered for these regions.
2024-09-17 14:41:56 +02:00
Silvris ce42e42af7
Core: fix single player item links (#3721)
* fix single player item links

* Make a variable and fix weird spacing

* use advancement instead of classification

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-09-17 14:36:05 +02:00
Star Rauchenberger ee12dda361
Lingo: Added missing connection from The Tenacious -> Hub Room (#3947) 2024-09-16 18:06:20 +02:00
Exempt-Medic 84805a4e54
HK: XBox doesn't exist #3932 2024-09-16 14:30:47 +02:00
Fabian Dill 5530d181da
Core: update version number (#3944) 2024-09-16 06:48:13 +02:00
Mysteryem ed948e3e5b
sm64ex: Add missing indirect condition for BitFS randomized entrance (#3926)
The Bowser in the Fire Sea randomized entrance has an access rule that
requires being able to reach "DDD: Board Bowser's Sub", but being able
to reach a location also requires being able to reach the region that
location is in, so an indirect condition is required.
2024-09-13 16:02:13 +02:00
Natalie Weizenbaum 7621889b8b
DS3: Add nex3 as a world maintainer (#3882)
I've already discussed this with @Marechal-L and gotten his approval.
2024-09-11 13:22:53 +02:00
Bryce Wilson c9f1a21bd2
BizHawkClient: Remove `run_gui` in favor of `make_gui` (#3910) 2024-09-11 13:22:04 +02:00
Bryce Wilson 874392756b
Pokemon Emerald: Add normalize encounter rate option to slot data (#3917) 2024-09-11 13:20:07 +02:00
Spineraks 7ff201e32c
Yacht Dice: add get_filler_item_name (#3916)
* Add the yacht dice (from other git) world to the yacht dice fork

* Update .gitignore

* Removed zillion because it doesn't work

* Update .gitignore

* added zillion again...

* Now you can have 0 extra fragments

* Added alt categories, also options

* Added item categories

* Extra categories are now working! 🐶

* changed options and added exceptions

* Testing if I change the generate.py

* Revert "Testing if I change the generate.py"

This reverts commit 7c2b3df6170dcf8d8f36a1de9fcbc9dccdec81f8.

* ignore gitignore

* Delete .gitignore

* Update .gitignore

* Update .gitignore

* Update logic, added multiplicative categories

* Changed difficulties

* Update offline mode so that it works again

* Adjusted difficulty

* New version of the apworld, with 1000 as final score, always

Will still need to check difficulty and weights of adding items.
Website is not ready yet, so this version is not usable yet :)

* Changed yaml and small bug fixes

Fix when goal and max are same
Options: changed chance to weight

* no changes, just whitespaces

* changed how logic works

Now you put an array of mults and the cpu gets a couple of tries

* Changed logic, tweaked a bit too

* Preparation for 2.0

* logic tweak

* Logic for alt categories properly now

* Update setup_en.md

* Update en_YachtDice.md

* Improve performance of add_distributions

* Formatting style

* restore gitignore to APMW

* Tweaked generation parameters and methods

* Version 2.0.3

manual input option
max score in logic always 2.0.3
faster gen

* Comments and editing

* Renamed setup guide

* Improved create_items code

* init of locations: remove self.event line

* Moved setting early items to generate_early

* Add my name to CODEOWNERS

* Added Yacht Dice to the readme in list of games

* Improve performance of Yacht Dice

* newline

* Improve typing

* This is actually just slower lol

* Update worlds/yachtdice/Items.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update Options.py

* Styling

* finished text whichstory option

* removed roll and rollfragments; not used

* import; worlds not world :)

* Option groups!

* ruff styling, fix

* ruff format styling!

* styling and capitalization of options

* small comment

* Cleaned up the "state_is_a_list" a little bit

* RUFF 🐶

* Changed filling the itempool for efficiency

Now, we start with 17 extra items in the item pool, it's quite likely you need at least 17 items (~80%?).
And then afterwards, we delete items if we overshoot the target of 1000, and add items if we haven't reached an achievable score of 1000 yet. Also, no need to recompute the entire logic when adding points.

* 🐶

* Removed plando "fix"

* Changed indent of score multiplier

* faster location function

* Comments to docstrings

* fixed making location closest to goal_score be goal_score

* options format

* iterate keys and values of a dict together

* small optimization ListState

* faster collection of categories

* return arguments instead of making a list (will 🐶 later)

* Instead of turning it into a tuple, you can just make a tuple literal

* remove .keys()

* change .random and used enumerate

* some readability improvements

* Remove location "0", we don't use that one

* Remove lookup_id_to_name entirely

I for sure don't use it, and as far as I know it's not one of the mandatory functions for AP, these are item_name_to_id and location_name_to_id.

* .append instead of += for single items, percentile function changed

Also an extra comment for location ids.

* remove ) too many

* Removed sorted from category list

* Hash categories (which makes it slower :( )

Maybe I messed up or misunderstood...
I'll revert this right away since it is 2x slower, probably because of sorted instead of sort?

* Revert "Hash categories (which makes it slower :( )"

This reverts commit 34f2c1aed8c8813b2d9c58896650b82a810d3578.

* temporary push: 40% faster generation test

Small changes in logic make the generation 40% faster.
I'll have to think about how big the changes are. I suspect they are rather limited.
If this is the way to go, I'll remove the temp file and redo the YachtWeights file, I'll remove the functions there and just put the new weights here.

* Add Points item category

* Reverse changes of bad idea :)

* ruff 🐶

* Use numpy and pmf function to speed up gen

Numpy has a built-in way to sum probability mass functions (pmf).
This shaves of 60% of the generation time :D

* Revert "Use numpy and pmf function to speed up gen"

This reverts commit 9290191cb323ae92321d6c2cfcfe8c27370f439b.

* Step inbetween to change the weights

* Changed the weights to make it faster

135 -> 81 seconds on 100 random yamls

* Adjusted max_dist, split dice_simulation function

* Removed nonlocal and pass arguments instead

* Change "weight-lists" to Dict[str, float]

* Removed the return from ini_locations.

Also added explanations to cat_weights

* Choice options; dont'use .value (will ruff later)

* Only put important options in slotdata

* 🐶

* Add Dict import

* Split the cache per player, limit size to 400.

* 🐶

* added , because of style

* Update apworld version to 2.0.6

2.0.5 is the apworld I released on github to be tested
I never separately released 2.0.4.

* Multiple smaller code improvements

- changed names in YachtWeights so we don't need to translate them in Rules anymore
- we now remember which categories are present in the game, and also put this in slotdata. This we do because only one of two categories is present in a game. If for some reason both are present (plando/getitem/startinventory), we now know which category to ignore
-

* 🐶 ruff

* Mostly minimize_extra_items improvements

- Change logic, generation is now even faster (0.6s per default yaml).
- Made the option 'minimize_extra_items' do a lot more, hopefully this makes the impact of Yacht Dice a little bit less, if you want that. Here's what is also does now:
 - you start with 2 dice and 2 rolls
 - there will be less locations/items at the start of you game

* ruff 🐶

* Removed printing options

* Reworded some option descriptions

* Yacht Dice: setup: change release-link to latest

On the installation page, link to the latest release, instead of the page with all releases

* Several fixes and changes

-change apworld version
-Removed the extra roll (this was not intended)
-change extra_points_added to a mutable list to that it actually does something
-removed variables multipliers_added and items_added
-Rules, don't order by quantity, just by mean_score
-Changed the weights in general to make it faster

* 🐶

* Revert setup to what it was (latest, without S)

* remove temp weights file, shouldn't be here

* Made sure that there is not too many step score multipliers.

Too many step score multipliers lead to gen fails too, probably because you need many categories for them to actually help a lot. So it's hard to use them at the start of the game.

* add filler item name

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-09-10 17:01:36 +02:00
NewSoupVi 170aedba8f
The Witness: Fix hints always displaying the Witness player (#3861)
* The Witness: Fix hints always displaying the Witness player

Got a bit too trigger happy with changing instances of `world.multiworld.player_name` to `world.player_name` - Some of these were actually *supposed* to be other players.

Alternate title: The Witness doesn't have a Silph Scope

* that one i guess
2024-09-09 17:36:47 +02:00
NewSoupVi 09c7f5f909
The Witness: Bump Required Client Version (#3891)
The newest release of the Witness client connects with 0.5.1

https://github.com/NewSoupVi/The-Witness-Randomizer-for-Archipelago/releases/tag/7.0.0p10
2024-09-09 17:36:27 +02:00
Silvris 4aab317665
ALTTP: Plando (#2904) fixes (#3834) 2024-09-09 15:56:15 +02:00
Exempt-Medic e52ce0149a
Rogue Legacy: Split Additional Names into two option classes #3908 2024-09-08 19:57:09 +02:00
Aaron Wagener 5a5162c9d3
The Messenger: improve automated installation (#3083)
* add deck support to the messenger mod setup

* Add tkinter cleanup because it's janky

* prompt about launching the game instead of just doing it

* add "better" file validation to courier checking

* make it a bit more palatable

* make it a bit more palatable

* add the executable's md5 to ensure the correct file is selected

* handle a bad md5 and show a message

* make the utils wrapper snake_case and add a docstring

* use stored archive instead of head

* don't give other people the convenience method ig
2024-09-08 19:55:17 +02:00
qwint cf375cbcc4
Core: Fix Generate's slot parsing to default unknown slot names to file name (#3795)
* make Generate handle slots without names defined better

* set name dict before loop so we don't have to check for its existence later

* move setter so it's more obvious why
2024-09-08 19:54:27 +02:00
Silvris 6d6d35d598
Rogue Legacy: Update to Options API (#3755)
* fix deprecation

* multiworld.random -> world.random

* Various small fixes

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: Exempt-Medic <ExemptMedic@Gmail.com>
2024-09-08 18:50:08 +02:00
Bryce Wilson 05b257adf9
Pokemon Emerald: Make use of `NamedTuple._replace` (#3727) 2024-09-08 18:48:48 +02:00
Jouramie cabfef669a
Stardew Valley: Fix masteries logic so it requires levels and tools (#3640)
* fix and add test

* add test to make sure we check xp can be earned

* fix python 3.8 test my god I hope it gets removed soon

* fixing some review comments

* curse you monstersanity

* move month rule to has_level vanilla, so next level is in logic once the previous item is received

* use progressive masteries to skills in test alsanity

* rename reset_collection_state

* add more tests around skill and masteries rules

* progressive level issue

---------

Co-authored-by: agilbert1412 <alexgilbert@yahoo.com>
2024-09-08 18:46:58 +02:00
qwint e4a5ed1cc4
CommonClient: Explicitly parse url arg as an archipelago:// url (#3568)
* Launcher "Text Client" --connect archipelago.gg:38281
should work, it doesn't, this fixes that

* more explicit handling of expected values

* removing launcher updates meaning this pr cannot stand alone but will not have merge issues later

* add parser failure when an invalid url is found

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-09-08 18:40:32 +02:00
qwint 5021997df0
Launcher: explicitly handle cli arguments to be passed to the Component (#3714)
* adds handling for the `--` cli arg by having launcher capture, ignore, and pass through all of the values after it, while only processing (and validating) the values before it
updates text client and its components to allow for args to be passed through, captured in run_as_textclient, and used in parse_args if present

* Update worlds/LauncherComponents.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* explicitly using default args for parse_args when launched directly

* revert manual arg parsing by request

* Update CommonClient.py

* Update LauncherComponents.py

* :)

---------

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-09-08 18:13:01 +02:00
neocerber d90cf0db65
SC2 EN/FR documentation update (#3440)
* Draft of SC2 EN documentation update: added hotkey, known issues; enhanced goal and prog balancing description. Added place holder for changes to apply in the French documentation.

* Enforced StarCraft over Starcraft, added information on locations in the FR documentation

* Removed a mention to a no longer available third link in the required software (since download_data deprecated the need to do it by hand)

* First version of FR campaign restriction for sc2; rewriting (FR/EN) of randomizer goal description

* Finished description for sc2 AP goal , minor formating

* Added, both en/fr, indications that logic is locations wise and not mission wise (i.e. you might need to dip)

* Enforced the 120 carac limit to last commit

* Removed mention of needing to use the weighted option page to exlcude unit/upgrades since it is not longer the case in AP v0.5.0

* Added mention of /received being different in SC2 client (both language). Added Known issues in the FR version.

* Simplified the text a bit and corrected some errors

* Enforced, again, Star-C-raft; setting -> option; applied sugg for readability enhancement
2024-09-08 14:46:34 +02:00
Scipio Wright dad228cd4a
TUNIC: Logic Rules Redux (#3544)
* Clean these functions up, get the hell out of here 5 parameter function

* Clean up a bunch of rules that no longer need to be multi-lined since the functions are shorter

* Clean up some range functions

* Update to use world instead of player like Vi recommended

* Fix merge conflict

* Create new options

* Slightly revise ls rule

* Update options.py

* Update options.py

* Add tedious option for ls

* Update laurels zips description

* Create new options

* Slightly revise ls rule

* Update options.py

* Update options.py

* Add tedious option for ls

* Update laurels zips description

* Creating structures to redo ladder storage rules

* Put together overworld ladder groups, remove tedious

* Write up the rules for the regular rules

* Update slot data and UT stuff

* Put new ice grapple stuff in er rules

* Ice grapple hard to get to fountain cross room

* More ladder data

* Wrote majority of overworld ladder rules

* Finish the ladder storage rules

* Update notes

* Add note

* Add well rail to the rules

* More rules

* Comment out logically irrelevant entrances

* Update with laurels_zip helper

* Add parameter to has_ice_grapple_logic for difficulty

* Add new parameter to has_ice_grapple_logic

* Move ice grapple chest to lower forest in ER/ladders

* Fix rule

* Finishing out hooking the new rules into the code

* Fix bugs

* Add more hard ice grapples

* Fix more bugs

* Shops my beloved

* Change victory condition back

* Remove debug stuff

* Update plando connections description

* Fix extremely rare bug

* Add well front -> back hard ladder storages

* Note in ls rules about knocking yourself down with bombs being out of logic

* Add atoll fuse with wand + hard ls

* Add some nonsense that boils down to activating the fuse in overworld

* Further update LS description

* Fix missing logic on bridge switch chest in upper zig

* Revise upper zig rule change to account for ER

* Fix merge conflict

* Fix formatting, fix rule for heir access after merge

* Add the shop sword logic stuff in

* Remove todo that was already done

* Fill out a to-do with some cursed nonsense

* Fix event in wrong region

* Fix missing cathedral -> elevator connection

* Fix missing cathedral -> elevator connection

* Add ER exception to cathedral -> elevator

* Fix secret gathering place issue

* Fix incorrect ls rule

* Move 3 locations to Quarry Back since they're easily accessible from the back

* Also update non-er region

* Remove redundant parentheses

* Add new test for a weird edge case in ER

* Slight option description updates

* Use has_ladder in spots where it wasn't used for some reason, add a comment

* Fix unit test for ER

* Update per exempt's suggestion

* Add back LogicRules as an invisible option, to not break old yamls

* Remove unused elevation from portal class

* Update ladder storage without items description

* Remove shop_scene stuff since it's no longer relevant in the mod by the time this version comes out

* Remove shop scene stuff from game info since it's no longer relevant in the mod by the time this comes out

* Update portal list to match main

* god I love github merging things

* Remove note

* Add ice grapple hard path from upper overworld to temple rafters entrance

* Actually that should be medium

* Remove outdated note

* Add ice grapple hard for swamp mid to the ledge

* Add missing laurels zip in swamp

* Some fixes to the ladder storage data while reviewing it

* Add unit test for weird edge case

* Backport outlet region system to fix ls bug

* Fix incorrect ls, add todo

* Add missing swamp ladder storage connections

* Add swamp zip to er data

* Add swamp zip to er rules

* Add hard ice grapple for forest grave path main to upper

* Add ice grapple logic for all bomb walls except the east quarry one

* Add ice grapple logic for frog stairs eye to mouth without the ladder

* Add hard ice grapple for overworld to the stairs to west garden

* Add the ice grapple boss quick kills to medium ice grappling

* Add the reverse connection for the ice grapple kill on Garden Knight

* Add atoll house ice grapple push, and add west garden ice grapple entry to the regular rules
2024-09-08 14:42:59 +02:00
Exempt-Medic a652108472
Docs: Update Trap classification comment #3485 2024-09-08 14:21:26 +02:00
Bryce Wilson 5348f693fe
Pokemon Emerald: Use some new state functions, improve rule reuse (#3383)
* Pokemon Emerald: Use some new state functions, improve rule reuse

* Pokemon Emerald: Remove a couple more extra lambdas

* Pokemon Emerald: Swap some rules to use exclusive groups/lists

* Pokemon Emerald: Linting

We're not gonna keep both me and the linter happy here, but this at least gets things more consistent

* Pokemon Emerald: Update _exclusive to _unique
2024-09-08 14:19:37 +02:00
qwint b8c2e14e8b
CommonClient: allow worlds to change title of run_gui without rewriting it (#3297)
* moves the title name in CommonContext.run_gui into a parameter defaulted to the normal default so others using it don't have to rewrite everything

* Change to using a GameManager attribute instead of a default param

* Update CommonClient.py

treble suggestion 1

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* Update CommonClient.py

treble suggestion 2

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* Update CommonClient.py

treble suggestion 3

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

* Use make_gui() instead of a property to push kivy importing back to lazy loading regardless of gui_enabled status

* cleanup

* almost forgot to type it

* change make_gui to be a class so clients can subclass it

* clean up code readability

---------

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-09-08 14:17:20 +02:00
Aaron Wagener 430b71a092
Core: have webhost slot name links go through the launcher (#2779)
* Core: have webhost slot name links go through the launcher so that components can use them

* fix query handling, remove debug prints, and change mousover text for new behavior

* remove a missed debug and unused function

* filter room id to suuid since that's what everything else uses

* pass args to common client correctly

* add GUI to select which client to open

* remove args parsing and "require" components to parse it themselves

* support for messenger since it was basically already done

* use "proper" args argparsing and clean up uri handling

* use a timer and auto launch text client if no component is found

* change the timer to be a bit more appealing. also found a bug lmao

* don't hold 5 hostage and capitalize URI ig

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-09-08 00:03:04 +02:00
Spineraks a40744e6db
Yacht Dice: logic fix and several other fixes (#3878)
* Add the yacht dice (from other git) world to the yacht dice fork

* Update .gitignore

* Removed zillion because it doesn't work

* Update .gitignore

* added zillion again...

* Now you can have 0 extra fragments

* Added alt categories, also options

* Added item categories

* Extra categories are now working! 🐶

* changed options and added exceptions

* Testing if I change the generate.py

* Revert "Testing if I change the generate.py"

This reverts commit 7c2b3df6170dcf8d8f36a1de9fcbc9dccdec81f8.

* ignore gitignore

* Delete .gitignore

* Update .gitignore

* Update .gitignore

* Update logic, added multiplicative categories

* Changed difficulties

* Update offline mode so that it works again

* Adjusted difficulty

* New version of the apworld, with 1000 as final score, always

Will still need to check difficulty and weights of adding items.
Website is not ready yet, so this version is not usable yet :)

* Changed yaml and small bug fixes

Fix when goal and max are same
Options: changed chance to weight

* no changes, just whitespaces

* changed how logic works

Now you put an array of mults and the cpu gets a couple of tries

* Changed logic, tweaked a bit too

* Preparation for 2.0

* logic tweak

* Logic for alt categories properly now

* Update setup_en.md

* Update en_YachtDice.md

* Improve performance of add_distributions

* Formatting style

* restore gitignore to APMW

* Tweaked generation parameters and methods

* Version 2.0.3

manual input option
max score in logic always 2.0.3
faster gen

* Comments and editing

* Renamed setup guide

* Improved create_items code

* init of locations: remove self.event line

* Moved setting early items to generate_early

* Add my name to CODEOWNERS

* Added Yacht Dice to the readme in list of games

* Improve performance of Yacht Dice

* newline

* Improve typing

* This is actually just slower lol

* Update worlds/yachtdice/Items.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update Options.py

* Styling

* finished text whichstory option

* removed roll and rollfragments; not used

* import; worlds not world :)

* Option groups!

* ruff styling, fix

* ruff format styling!

* styling and capitalization of options

* small comment

* Cleaned up the "state_is_a_list" a little bit

* RUFF 🐶

* Changed filling the itempool for efficiency

Now, we start with 17 extra items in the item pool, it's quite likely you need at least 17 items (~80%?).
And then afterwards, we delete items if we overshoot the target of 1000, and add items if we haven't reached an achievable score of 1000 yet. Also, no need to recompute the entire logic when adding points.

* 🐶

* Removed plando "fix"

* Changed indent of score multiplier

* faster location function

* Comments to docstrings

* fixed making location closest to goal_score be goal_score

* options format

* iterate keys and values of a dict together

* small optimization ListState

* faster collection of categories

* return arguments instead of making a list (will 🐶 later)

* Instead of turning it into a tuple, you can just make a tuple literal

* remove .keys()

* change .random and used enumerate

* some readability improvements

* Remove location "0", we don't use that one

* Remove lookup_id_to_name entirely

I for sure don't use it, and as far as I know it's not one of the mandatory functions for AP, these are item_name_to_id and location_name_to_id.

* .append instead of += for single items, percentile function changed

Also an extra comment for location ids.

* remove ) too many

* Removed sorted from category list

* Hash categories (which makes it slower :( )

Maybe I messed up or misunderstood...
I'll revert this right away since it is 2x slower, probably because of sorted instead of sort?

* Revert "Hash categories (which makes it slower :( )"

This reverts commit 34f2c1aed8c8813b2d9c58896650b82a810d3578.

* temporary push: 40% faster generation test

Small changes in logic make the generation 40% faster.
I'll have to think about how big the changes are. I suspect they are rather limited.
If this is the way to go, I'll remove the temp file and redo the YachtWeights file, I'll remove the functions there and just put the new weights here.

* Add Points item category

* Reverse changes of bad idea :)

* ruff 🐶

* Use numpy and pmf function to speed up gen

Numpy has a built-in way to sum probability mass functions (pmf).
This shaves of 60% of the generation time :D

* Revert "Use numpy and pmf function to speed up gen"

This reverts commit 9290191cb323ae92321d6c2cfcfe8c27370f439b.

* Step inbetween to change the weights

* Changed the weights to make it faster

135 -> 81 seconds on 100 random yamls

* Adjusted max_dist, split dice_simulation function

* Removed nonlocal and pass arguments instead

* Change "weight-lists" to Dict[str, float]

* Removed the return from ini_locations.

Also added explanations to cat_weights

* Choice options; dont'use .value (will ruff later)

* Only put important options in slotdata

* 🐶

* Add Dict import

* Split the cache per player, limit size to 400.

* 🐶

* added , because of style

* Update apworld version to 2.0.6

2.0.5 is the apworld I released on github to be tested
I never separately released 2.0.4.

* Multiple smaller code improvements

- changed names in YachtWeights so we don't need to translate them in Rules anymore
- we now remember which categories are present in the game, and also put this in slotdata. This we do because only one of two categories is present in a game. If for some reason both are present (plando/getitem/startinventory), we now know which category to ignore
-

* 🐶 ruff

* Mostly minimize_extra_items improvements

- Change logic, generation is now even faster (0.6s per default yaml).
- Made the option 'minimize_extra_items' do a lot more, hopefully this makes the impact of Yacht Dice a little bit less, if you want that. Here's what is also does now:
 - you start with 2 dice and 2 rolls
 - there will be less locations/items at the start of you game

* ruff 🐶

* Removed printing options

* Reworded some option descriptions

* Yacht Dice: setup: change release-link to latest

On the installation page, link to the latest release, instead of the page with all releases

* Several fixes and changes

-change apworld version
-Removed the extra roll (this was not intended)
-change extra_points_added to a mutable list to that it actually does something
-removed variables multipliers_added and items_added
-Rules, don't order by quantity, just by mean_score
-Changed the weights in general to make it faster

* 🐶

* Revert setup to what it was (latest, without S)

* remove temp weights file, shouldn't be here

* Made sure that there is not too many step score multipliers.

Too many step score multipliers lead to gen fails too, probably because you need many categories for them to actually help a lot. So it's hard to use them at the start of the game.

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-09-06 22:50:57 +02:00
Draexzhan d802f9652a
Webhost: Fixed typo in userContent.html #3896
Changed "no" to "not"
2024-09-06 20:40:21 +02:00
NewSoupVi cbdb4d7ce3
CODEOWNERS: Move OoT to "unmaintained" (#3894)
https://discord.com/channels/731205301247803413/1214608557077700720/1253206955879694336

Espeon might come back, but still, this world acts as unmaintained right now, so we should make this change, and then change it back if/when he's back.

@espeon65536 Just so you're aware of this change as well
2024-09-06 19:38:18 +02:00
Mysteryem 691ce6a248
The Witness: Fix nondeterministic entity hunt (#3892)
In `_get_next_random_batch()`, the `remaining_entities` and
`remaining_entity_weights` lists were being constructed by iterating
sets.

This patch changes the function to iterate a sorted copy of each set
instead.
2024-09-06 19:23:16 +02:00
Danaël V. f9fc6944d3
Docs: Removing #archipelago-dev from places (#3876)
* Cleaning up (#4)

Cleanup

* Changed channel name

* Changed channel name

* Update docs/world maintainer.md

* Update docs/world maintainer.md
2024-09-05 22:55:19 +02:00
qwint e984583e5e
HK: speed up collect (a bit) (#3886)
* speed up collect, will be obsolete after #3786

* vi's a meanie
2024-09-05 21:19:37 +02:00
Exempt-Medic 7e03a87608
DOCS: Option Visibility and removing SpecialRange (#3889)
* Update options api.md

* Update options api.md

* Update docs/options api.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

---------

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
2024-09-05 21:18:58 +02:00
NewSoupVi 456bc481a3
Docs: Specify process for adding a world maintainer to an existing world (#3884)
* Docs: Specify process for adding a world maintainer to an existing world

* Update world maintainer.md

* Update world maintainer.md

* Update world maintainer.md

* Update world maintainer.md

* Update world maintainer.md

* Update world maintainer.md

* Update world maintainer.md

* Update world maintainer.md

* Update world maintainer.md

* Update world maintainer.md

* Update world maintainer.md

* Rewrite by BadMagic

* Update docs/world maintainer.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-09-05 21:16:44 +02:00
NewSoupVi b4752cd32d
The Witness: Implement "Variety" puzzles mode (#3239)
* Variety Rando (But WitnessLogicVariety.txt is wrong

* Actually variety the variety file (Ty Exempt-Medic <3)

* This will be preopened

* Tooltip explaining the different difficulties

* Remove ?, those were correct

* Less efficient but easier to follow

* Parentheses

* Fix some reqs

* Not Arrows in Variety

* Oops

* Happy medic, I made a wacky solution

* there we go

* Lint oops

* There

* that copy is unnecessary

* Turns out that copy is necessary still

* yes

* lol

* Rename to Umbra Variety

* missed one

* Erase the Eraser

* Fix remaining instances of 'variety' and don't have a symbol item on the gate in variety

* reorder difficulties

* inbetween

* ruff

* Fix Variety Invis requirements

* Fix wooden beams variety

* Fix PP2 variety

* Mirror changes from 'Variety Mode Puzzle Change 3.2.3'

* These also have Symmetry

* merge error prevention

* Update worlds/witness/data/static_items.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* no elif after return

* add variety to the symbol requirement bleed test

* Add variety to one of the 'other settings' unit tests

* Add Variety minimal symbols unittest

* oops

* I did the dumb again

* .

* Incorporate changes from other PR into WitnesLogicVariety.txt

* Update worlds/witness/data/WitnessLogicVariety.txt

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/witness/data/WitnessLogicVariety.txt

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update the reqs as well haha

* Another difference, thanks Medic :§

* Wait no, this one was right

* lol

* apply changes to WitnessLogicVariety.txt

* Add most recent Variety changes

* oof

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-09-05 17:10:09 +02:00
Fabian Dill ceec51b9e1
Core: Region handling customization (#3682) 2024-09-05 16:32:45 +02:00
NewSoupVi d3312287a8
Docs: Mention indirect_conditions and that they are a *hard requirement* (with a few sharp exception cases) (#3552)
* Docs: Mention indirect_conditions and that they are a *hard requirement* (with hard exception cases)

I definitely don't feel like I wrote this in the best way, or in the best place, but it is a precedent that I think is necessary so we can treat it as "the law of the land".

* oops

* Update world api.md

* Update world api.md

* Update world api.md

* Update docs/world api.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* I like within more here

* Update docs/world api.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update world api.md

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-09-05 13:53:34 +02:00
Bryce Wilson d65863ffa2
Pokemon Emerald: Fix wrong place for initialization (#3870) 2024-09-04 20:00:47 +02:00
Aaron Wagener b8d7ef24f7
The Messenger: remove an invalid entrance (#3873) 2024-09-04 15:21:02 +02:00
Silvris b2949dfbe8
KDL3: Account for additional animal in pool #3874 2024-09-04 15:19:00 +02:00
black-sliver 2aa0653b6d
WebHost: update dependencies (#3871) 2024-09-03 02:31:42 +02:00
black-sliver d63efa5846
Core: update dependencies (#3869) 2024-09-03 02:22:48 +02:00
Fabian Dill 765721888a
WebHost: config override (#3701) 2024-09-03 01:26:46 +02:00
black-sliver 73701292b5
Core, CI: Add Python 3.12 support (#3290)
* Core, CI: add py3.12 compat

* Stardew Valley: Fix tests for Py3.12

* ModuleUpdate: always install pkg_resources

* Docs: update supported python versions

* WebHost: update pony to upstream 0.7.18

* CI: test hosting update to py3.12

* Update docs/running from source.md
2024-09-02 10:08:16 +02:00
Fabian Dill 3ab71daa8d
MultiServer: put some limits in place (#3858)
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2024-09-01 21:59:37 +02:00
NewSoupVi 6f46397185
Rogue Legacy: Crash generation when there are overlapping IDs (#3865)
Client literally does not work when there are overlapping IDs.

Phar is not currently intending to fix it.

https://discord.com/channels/731205301247803413/929585237695029268/1269684436853723156
2024-09-01 21:41:55 +02:00
black-sliver 1a41e1acc8
customserver: fix memory leak (#3864) 2024-09-01 20:34:50 +02:00
Scipio Wright 34a3b5f058
TUNIC: Add alias for Ladders in Overworld Town #3862 2024-08-31 23:37:18 +02:00
Exempt-Medic 456b4adaa1
ALttP/Docs: Correcting the plando docs (#3835)
* Correcting some text

* Reword sentence
2024-08-31 23:36:29 +02:00
NewSoupVi fc8462f4e9
The Witness: Add Beginner Mode option preset #3691 2024-08-31 22:51:41 +02:00
Mysteryem 499dad53b1
AHIT: Fix thug shops having 0 items after the first shop rolls 0 items (#3799)
Once a thug shop rolled 0 as the number of items it should have, all
remaining iterations would do nothing because neither the `count == -1`
condition nor the `count >= 1` condition would be met. This caused all
remaining thug shops to have zero items. This also caused the item
counts of remaining thug shops to be absent from slot data, which was
how this issue was found.

I found the old code confusing and, rather than try to figure out how to
fix it, I opted to rewrite it. With the new code, a local variable
dictionary tracks the number of created locations for each thug and no
more locations are created for a thug once their number of locations
equals the number of shop items that thug rolled.
2024-08-31 21:00:19 +02:00
agilbert1412 8a809be67a
Stardew Valley - Prize Ticket and Mystery Box grinding requires the abilty to redeem them #3728 2024-08-31 20:57:43 +02:00
lordlou 7e0219c214
SM and SMZ3 option_definitions deprecation fix (#3372)
* - reenabled balancing

* post rebase fixes

* updated SmClient.py

* + added VariaRandomizer LICENSE

* + added sm_randomizer_rom project (which builds sm.ips)

* Moved VariaRandomizer and sm_randomizer_rom projects inside worlds/sm and done some cleaning

* properly revert change made to CollectionState and more cleaning

* Fixed multiworld support patch not working with VariaRandomizer's

* missing file commit

* Fixed syntax error in unused code to satisfy Linter

* Revert "Fixed multiworld support patch not working with VariaRandomizer's"

This reverts commit fb3ca18528bb331995e3d3051648c8f84d04c08b.

* many fixes and improovement

- fixed seeded generation
- fixed broken logic when more than one SM world
- added missing rules for inter-area transitions
- added basic patch presence for logic
- added DoorManager init call to reflect present patches for logic
- moved CollectionState addition out of BaseClasses into SM world
- added condition to apply progitempool presorting only if SM world is present
- set Bosses item id to None to prevent them going into multidata
- now use get_game_players

* first working (most of the time) progression generation for SM using VariaRandomizer's rules, items, locations and accessPoint (as regions)

* first working single-world randomized SM rom patches

* - SM now displays message when getting an item outside for someone else (fills ROM item table)

This is dependant on modifications done to sm_randomizer_rom project

* First working MultiWorld SM

* some missing things:

- player name inject in ROM and get in client
- end game get from ROM in client
- send self item to server
- add player names table in ROM

* replaced CollectionState inheritance from SMBoolManager with a composition of an array of it (required to generation more than one SM world, which is still fails but is better)

* - reenabled balancing

* post rebase fixes

* updated SmClient.py

* + added VariaRandomizer LICENSE

* + added sm_randomizer_rom project (which builds sm.ips)

* Moved VariaRandomizer and sm_randomizer_rom projects inside worlds/sm and done some cleaning

* properly revert change made to CollectionState and more cleaning

* Fixed multiworld support patch not working with VariaRandomizer's

* missing file commit

* Fixed syntax error in unused code to satisfy Linter

* Revert "Fixed multiworld support patch not working with VariaRandomizer's"

This reverts commit fb3ca18528bb331995e3d3051648c8f84d04c08b.

* many fixes and improovement

- fixed seeded generation
- fixed broken logic when more than one SM world
- added missing rules for inter-area transitions
- added basic patch presence for logic
- added DoorManager init call to reflect present patches for logic
- moved CollectionState addition out of BaseClasses into SM world
- added condition to apply progitempool presorting only if SM world is present
- set Bosses item id to None to prevent them going into multidata
- now use get_game_players

* Fixed multiworld support patch not working with VariaRandomizer's

Added stage_fill_hook to set morph first in progitempool
Added back VariaRandomizer's standard patches

* + added missing files from variaRandomizer project

* + added missing variaRandomizer files (custom sprites)

+ started integrating VariaRandomizer options (WIP)

* Some fixes for player and server name display

- fixed player name of 16 characters reading too far in SM client
- fixed 12 bytes SM player name limit (now 16)
- fixed server name not being displayed in SM when using server cheat ( now displays RECEIVED FROM ARCHIPELAGO)
- request: temporarly changed default seed names displayed in SM main menu to OWTCH

* Fixed Goal completion not triggering in smClient

* integrated VariaRandomizer's options into AP (WIP)

- startAP is working
- door rando is working
- skillset is working

* - fixed itemsounds.ips crash by always including nofanfare.ips into multiworld.ips (itemsounds is now always applied and "itemsounds" preset must always be "off")

* skillset are now instanced per player instead of being a singleton class

* RomPatches are now instanced per player instead of being a singleton class

* DoorManager is now instanced per player instead of being a singleton class

* - fixed the last bugs that prevented generation of >1 SM world

* fixed crash when no skillset preset is specified in randoPreset (default to "casual")

* maxDifficulty support and itemsounds removal

- added support for maxDifficulty
- removed itemsounds patch as its always applied from multiworld patch for now

* Fixed bad merge

* Post merge adaptation

* fixed player name length fix that got lost with the merge

* fixed generation with other game type than SM

* added default randoPreset json for SM in playerSettings.yaml

* fixed broken SM client following merge

* beautified json skillset presets

* Fixed ArchipelagoSmClient not building

* Fixed conflict between mutliworld patch and beam_doors_plms patch

- doorsColorsRando now working

* SM generation now outputs APBP

- Fixed paths for patches and presets when frozen

* added missing file and fixed multithreading issue

* temporarily set data_version = 0

* more work

- added support for AP starting items
- fixed client crash with gamemode being None
- patch.py "compatible_version" is now 3

* commited missing asm files

fixed start item reserve breaking game (was using bad write offset when patching)

* Nothing item are now handled game-side. the game will now skip displaying a message box for received Nothing item (but the client will still receive it).

fixed crash in SMClient when loosing connection to SNI

* fixed No Energy Item missing its ID

fixed Plando

* merge post fixes

* fixed start item Grapple, XRay and Reserve HUD, as well as graphic beams (except ice palette color)

* fixed freeze in blue brinstar caused by Varia's custom PLM not being filled with proper Multiworld PLM address (altLocsAddresses)

* fixed start item x-ray HUD display

* Fixed start items being sent by the server (is all handled in ROM)

Start items are now not removed from itempool anymore
Nothing Item is now local_items so no player will ever pickup Nothing. Doing so reduces contribution of this world to the Multiworld the more Nothing there is though.
Fixed crash (and possibly passing but broken) at generation where the static list of IPSPatches used by all SM worlds was being modified

* fixed settings that could be applied to any SM players

* fixed auth to server only using player name (now does as ALTTP to authenticate)

* - fixed End Credits broken text

* added non SM item name display

* added all supported SM options in playerSettings.yaml

* fixed locations needing a list of parent regions (now generate a region for each location with one-way exits to each (previously) parent region

did some cleaning (mainly reverts on unnecessary core classes

* minor setting fixes and tweaks

- merged Area and lightArea settings
- made missileQty, superQty and powerBombQty use value from 10 to 90 and divide value by float(10) when generating
- fixed inverted layoutPatch setting

* added option start_inventory_removes_from_pool

fixed option names formatting
fixed lint errors
small code and repo cleanup

* Hopefully fixed ROR2 that could not send any items

* - fixed missing required change to ROR2

* fixed 0 hp when respawning without having ever saved (start items were not updating the save checksum)

* fixed typo with doors_colors_rando

* fixed checksum

* added custom sprites for off-world items (progression or not)

the original AP sprite was made with PierRoulette's SM Item Sprite Utility by ijwu

* - added missing change following upstream merge

- changed patch filename extension from apbp to apm3 so patch can be used with the new client

* added morph placement options: early means local and sphere 1

* fixed failing unit tests

* - fixed broken custom_preset options

* - big cleanup to remove unnecessary or unsupported features

* - more cleanup

* - moved sm_randomizer_rom and all always applied patches into an external project that outputs basepatch.ips

- small cleanup

* - added comment to refer to project for generating basepatch.ips (https://github.com/lordlou/SMBasepatch)

* fixed g4_skip patch that can be not applied if hud is enabled

* - fixed off world sprite that can have broken graphics (restricted to use only first 2 palette)

* - updated basepatch to reflect g4_skip removal

- moved more asm files to SMBasepatch project

* - tourian grey doors at baby metroid are now always flashing (allowing to go back if needed)

* fixed wrong path if using built as exe

* - cleaned exposed maxDifficulty options

- removed always enabled Knows

* Merged LttPClient and SMClient into SNIClient

* added varia_custom Preset Option that fetch a preset (read from a new varia_custom_preset Option) from varia's web service

* small doc precision

* - added death_link support

- fixed broken Goal Completion
- post merge fix

* - removed now useless presets

* - fixed bad internal mapping with maxDiff

- increases maxDiff if only Bosses is preventing beating the game

* - added support for lowercase custom preset sections (knows, settings and controller)

- fixed controller settings not applying to ROM

* - fixed death loop when dying with Door rando, bomb or speed booster as starting items

- varia's backup save should now be usable (automatically enabled when doing door rando)

* -added docstring for generated yaml

* fixed bad merge

* fixed broken infinity max difficulty

* commented debug prints

* adjusted credits to mark progression speed and difficulty as Non Available

* added support for more than 255 players (will print Archipelago for higher player number)

* fixed missing cleanup

* added support for 65535 different player names in ROM

* fixed generations failing when only bosses are unreachable

* - replaced setting maxDiff to infinity with a bool only affecting boss logics if only bosses are left to finish

* fixed failling generations when using 'fun' settings

Accessibility checks are forced to 'items' if restricted locations are used by VARIA following usage of 'fun' settings

* fixed debug logger

* removed unsupported "suits_restriction" option

* fixed generations failing when only bosses are unreachable (using a less intrusive approach for AP)

* - fixed deathlink emptying reserves

- added death_link_survive option that lets player survive when receiving a deathlink if the have non-empty reserves

* - merged death_link and death_link_survive options

* fixed death_link

* added a fallback default starting location instead of failing generation if an invalid one was chosen

* added Nothing and NoEnergy as hint blacklist

added missing NoEnergy as local items and removed it from progression

* replaced deprecated use of option_definitions for SM and SMZ3 by options_dataclass

* fixed missed references to option_definitions

* Update worlds/sm/variaRandomizer/utils/utils.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* fixed conflicts and made SMZ3 accessibility related code more future proof

* Update worlds/smz3/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/smz3/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-31 13:49:33 +02:00
Exempt-Medic b37bb60891
DS3: Prevent prioritized+excluded locations (#3855) 2024-08-31 13:44:48 +02:00
Natalie Weizenbaum f81335d614
DS3: Don't return early in the location loop (#3856)
This caused behavior errors when some locations in a group were
excluded and others were not.
2024-08-31 13:44:09 +02:00
Kory Dondzila 8ed466bf24
Shivers: Add collect behavior option. (#3854)
* Add collect behavior option.

* Add comma

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2024-08-31 13:30:42 +02:00
Silvris 920cffda2d
KDL3: Version 2.0.0 (#3323)
* initial work on procedure patch

* more flexibility

load default procedure for version 5 patches
add args for procedure
add default extension for tokens and bsdiff
allow specifying additional required extensions for generation

* pushing current changes to go fix tloz bug

* move tokens into a separate inheritable class

* forgot the commit to remove token from ProcedurePatch

* further cleaning from bad commit

* start on docstrings

* further work on docstrings and typing

* improve docstrings

* fix incorrect docstring

* cleanup

* clean defaults and docstring

* define interface that has only the bare minimum required
for `Patch.create_rom_file`

* change to dictionary.get

* remove unnecessary if statement

* update to explicitly check for procedure, restore compatible version and manual override

* Update Files.py

* remove struct uses

* Update Rom.py

* convert KDL3 to APPP

* change class variables to instance variables

* Update worlds/Files.py

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

* Update worlds/Files.py

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

* move required_extensions to tuple

* fix missing tuple ellipsis

* fix classvar mixup

* rename tokens to _tokens. use hasattr

* type hint cleanup

* Update Files.py

* initial base for local items, need to finish

* coo not clean

* handle local items for real, appp cleanup

* actually make bosses send their locations

* fix cloudy park 4 rule, zero deathlink message

* remove redundant door_shuffle bool

when generic ER gets in, this whole function gets rewritten. So just clean it a little now.

* properly fix deathlink messages, fix fill error

* update docs

* add prefill items

* fix kine fill error

* Update Rom.py

* Update Files.py

* mypy and softlock fix

* Update Gifting.py

* mypy phase 1

* fix rare async client bug

* Update __init__.py

* typing cleanup

* fix stone softlock

because of the way Kine's Stone works, you can't clear the stone blocks before clearing the burning blocks, so we have to bring Burning from outside

* Update Rom.py

* Add option groups

* Rename to lowercase

* finish rename

* whoops broke the world

* fix animal duplication bug

* overhaul filler generation

* add Miku flavor

* Update gifting.py

* fix issues related to max_hs increase

* Update test_locations.py

* fix boss shuffle not working if level shuffle is disabled

* fix bleeding default levels

* Update options.py

* thought this would print seed

* yay bad merges

* forgot options too

* yeah lets just break generation while at it

* this is probably a problem

* cap required heart stars

* Revert "cap required heart stars"

This reverts commit 759efd3e2b14ec2855082de041ac989cb9c5d500.

* fix duplication removal placement, deprecated test option

* forgot that we need to account for what we place

* move location ids

* rewrite trap handling

* further stage renumber fixes

* forgot one more

* basic UT support

* fix local heart star checks

* fix pattern

---------

Co-authored-by: beauxq <beauxq@yahoo.com>
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-08-31 13:15:00 +02:00
Natalie Weizenbaum b1be597451
DS3: Explicitly track item equality by name when sending IDs (#3853)
We had been keeping a set of items and defining item equality, but
item equality really only makes sense if you consider distinct IDs to
be distinct items. But that means the set ends up having multiple
copies of the same item, causing a bug where some items had the wrong
upgrade level in the game.

This also removes the equality definition, which was only used by this
one set.
2024-08-30 12:26:49 +02:00
Scipio Wright 08dc7e522e
TUNIC: Add note about plando items to ER hint-creation failure error message (#3825)
* Add note about plando items to entrance rando option description

* Update error text to specifically call out plando items

* Remove option description change
2024-08-29 09:42:46 +02:00
Exempt-Medic 0f64bd08e1
ChecksFinder: itempool naming/typing (#3797)
* Rename itempool

* Update comment
2024-08-29 08:43:13 +02:00
agilbert1412 d52827ebd2
Stardew Valley: Fix Crimsonfish region (#3687)
* - Add Unit test for all the fish that require a specific region to be reachable

* - Move the crimsonfish to the tide pools region

* - Improved the unit test to be more thorough, add extended family fish to the test

* - Moved the son of crimsonfish to the correct region as well

* FFMQ: Fix reset protection (#3710)

* Revert reset protection

* Fix reset protection

---------

Co-authored-by: alchav <alchav@jalchavware.com>

* - Take shipsanity moss out of shipsanity crops (#3709)

* sc2: Removing unused dependency in requirements.txt (#3697)

* sc2: Removing unused dependency in requirements.txt

* sc2: Add missing newline in requirements.txt

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* WebHost: Fix NamedRange values clamping to the range (#3613)

If a NamedRange has a `special_range_names` entry outside the
`range_start` and `range_end`, the HTML5 range input will clamp the
submitted value to the closest value in the range.

These means that, for example, Pokemon RB's "HM Compatibility" option's
"Vanilla (-1)" option would instead get posted as "0" rather than "-1".

This change updates NamedRange to behave like TextChoice, where the
select element has a `name` attribute matching the option, and there is
an additional element to be able to provide an option other than the
select element's choices.

This uses a different suffix of `-range` rather than `-custom` that
TextChoice uses. The reason is we need some way to decide whether to use
the custom value or the select value, and that method needs to work
without JavaScript. For TextChoice this is easy, if the custom field is
empty use the select element. For NamedRange this is more difficult as
the browser will always submit *something*. My choice was to only use
the value from the range if the select box is set to "custom". Since
this only happens with JS as "custom' is hidden, I made the range hidden
under no-JS. If it's preferred, I could make the select box hidden
instead. Let me know.

This PR also makes the `js-required` class set `display: none` with
`!important` as otherwise the class wouldn't work on any rule that
had `display: flex` with more specificity than a single class.

* Timespinner: migrate to new options api and correct random (#2485)

* Implemented new options system into Timespinner

* Fixed typo

* Fixed typo

* Fixed slotdata maybe

* Fixes

* more fixes

* Fixed failing unit tests

* Implemented options backwards comnpatibility

* Fixed option fallbacks

* Implemented review results

* Fixed logic bug

* Fixed python 3.8/3.9 compatibility

* Replaced one more multiworld option usage

* Update worlds/timespinner/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Updated logging of options replacement to include player name and also write it to spoiler
Fixed generation bug
Implemented review results

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Core: migrate item links out of main (#2914)

* Core: move item linking out of main

* add a test that item link option correctly validates

* remove unused fluff

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>

* Core: Rework accessibility (#1481)

* rename locations accessibility to "full" and make old locations accessibility debug only

* fix a bug in oot

* reorder lttp tests to not override its overrides

* changed the wrong word in the dict

* :forehead:

* update the manual lttp yaml

* use __debug__

* update pokemon and messenger

* fix conflicts from 993

* fix stardew presets

* add that locations may be inaccessible to description

* use reST format and make the items description one line so that it renders correctly on webhost

* forgot i renamed that

* add aliases for back compat

* some cleanup

* fix imports

* fix test failure

* only check "items" players when the item is progression

* Revert "only check "items" players when the item is progression"

This reverts commit ecbf986145e6194aa99a39c481d8ecd0736d5a4c.

* remove some unnecessary diffs

* CV64: Add ItemsAccessibility

* put items description at the bottom of the docstring since that's it's visual order

* :

* rename accessibility reference in pokemon rb dexsanity

* make the rendered tooltips look nicer

* Shivers: New features and removes two missed options using the old options API (#3287)

* Adds an option to have pot pieces placed local/non-local/anywhere

Shivers nearly always finishes last in multiworld games due to the fact you need all 20 pot pieces to win and the pot pieces open very few location checks. This option allows the pieces to be placed locally. This should allow Shivers to be finished earlier.

* New option: Choose how many ixupi captures are needed for goal completion

New option: Choose how many ixupi captures are needed for goal completion

* Fixes rule logic for location 'puzzle solved three floor elevator'

Fixes rule logic for location 'puzzle solved three floor elevator'. Missing a parenthesis caused only the key requirement to be checked for the blue maze region.

* Merge branch 'main' of https://github.com/GodlFire/Shivers

* Revert "Merge branch 'main' of https://github.com/GodlFire/Shivers"

This reverts commit bb08c3f0c2ef148fd24d7c7820cdfe936f7196e2.

* Fixes issue with office elevator rule logic.

* Bug fix, missing logic requirement for location 'Final Riddle: Guillotine Dropped'

Bug fix, missing logic requirement for location 'Final Riddle: Guillotine Dropped'

* Moves plaque location to front for better tracker referencing.

* Tiki should be Shaman.

* Hanging should be Gallows.

* Merrick spelling.

* Clarity change.

* Changes new option to use new option API

Changes new option to use new option API

* Added sub regions for Ixupi

-Added sub regions for Ixupi and moved ixupi capture checks into the sub region.
-Added missing wax capture possible spot in Shaman room

* Adds option for ixupi captures to be priority locations

Adds option for ixupi captures to be priority locations

* Consistency

Consistency

* Changes ixupi captures priority to default on toggle

Changes ixupi captures priority to default on toggle

* Docs update

-Updated link to randomizer
-Update some text to reflect the latest functionality
-Replaced 'setting' with 'option'

* New features/bug fixes

-Adds an option to have completed pots in the item pool
-Moved subterranean world information plaque to maze staircase

* Cleanup

Cleanup

* Fixed name for moved location

When moving a location and renaming it I forgot to fix the name in a second spot.

* Squashed commit of the following:

commit 630a3bdfb9414d8c57154f29253fce0cf67b6436
Merge: 8477d3c8 5e579200
Author: GodlFire <46984098+GodlFire@users.noreply.github.com>
Date:   Mon Apr 1 19:08:48 2024 -0600

    Merge pull request #10 from ArchipelagoMW/main

    Merge main into branch

commit 5e5792009c
Author: Alchav <59858495+Alchav@users.noreply.github.com>
Date:   Mon Apr 1 12:08:21 2024 -0500

    LttP: delete playerSettings.yaml (#3062)

commit 9aeeeb077a
Author: CaitSith2 <d_good@caitsith2.com>
Date:   Mon Apr 1 06:07:56 2024 -0700

    ALttP: Re-mark light/dark world regions after applying plando connections (#2964)

commit 35458380e6
Author: Bryce Wilson <gyroscope15@gmail.com>
Date:   Mon Apr 1 07:07:11 2024 -0600

    Pokemon Emerald: Fix wonder trade race condition (#2983)

commit 4ac1866689
Author: Alchav <59858495+Alchav@users.noreply.github.com>
Date:   Mon Apr 1 08:06:31 2024 -0500

    ALTTP: Skull Woods Inverted fix (#2980)

commit 4aa03da66e
Author: Fabian Dill <Berserker66@users.noreply.github.com>
Date:   Mon Apr 1 15:06:02 2024 +0200

    Factorio: fix attempting to create savegame with not filename safe characters (#2842)

commit 24a03bc8b6
Author: Silvris <58583688+Silvris@users.noreply.github.com>
Date:   Mon Apr 1 08:02:26 2024 -0500

    KDL3: fix shuffled animals not actually being random (#3060)

commit f813a7005f
Author: Aaron Wagener <mmmcheese158@gmail.com>
Date:   Sun Mar 31 11:11:10 2024 -0500

    The Messenger: update docs formatting and fix outdated info (#3033)

    * The Messenger: update docs formatting and fix outdated info

    * address review feedback

    * 120 chars

commit 2a0b7e0def
Author: LiquidCat64 <74896918+LiquidCat64@users.noreply.github.com>
Date:   Sun Mar 31 09:55:55 2024 -0600

    CV64: A couple of very small docs corrections. (#3057)

commit 03d47e460e
Author: Ixrec <ericrhitchcock@gmail.com>
Date:   Sun Mar 31 16:55:08 2024 +0100

    A Short Hike: Clarify installation instructions (#3058)

    * Clarify installation instructions

    * don't mention 'config' folder since it isn't created until the game starts

commit e546c0f7ff
Author: Silvris <58583688+Silvris@users.noreply.github.com>
Date:   Sun Mar 31 10:50:31 2024 -0500

    Yoshi's Island: add patch suffix (#3061)

commit 2ec93ba82a
Author: Bryce Wilson <gyroscope15@gmail.com>
Date:   Sun Mar 31 09:48:59 2024 -0600

    Pokemon Emerald: Fix inconsistent location name (#3065)

commit 4e3d396394
Author: Aaron Wagener <mmmcheese158@gmail.com>
Date:   Sun Mar 31 10:47:11 2024 -0500

    The Messenger: Fix precollected notes not being removed from the itempool (#3066)

    * The Messenger: fix precollected notes not being properly removed from pool

    * The Messenger: bump required client version

commit 72c53513f8
Author: Fabian Dill <Berserker66@users.noreply.github.com>
Date:   Sun Mar 31 03:57:59 2024 +0200

    WebHost: fix /check creating broken yaml files if files don't end with a newline (#3063)

commit b7ac6a4cbd
Author: Aaron Wagener <mmmcheese158@gmail.com>
Date:   Fri Mar 29 20:14:53 2024 -0500

    The Messenger: Fix various portal shuffle issues (#2976)

    * put constants in a bit more sensical order

    * fix accidental incorrect scoping

    * fix plando rules not being respected

    * add docstrings for the plando functions

    * fix the portal output pools being overwritten

    * use shuffle and pop instead of removing by content so plando can go to the same area twice

    * move portal pool rebuilding outside mapping creation

    * remove plando_connection cleansing since it isn't shared with transition shuffle

commit 5f0112e783
Author: Zach Parks <zach@alliware.com>
Date:   Fri Mar 29 19:13:51 2024 -0500

    Tracker: Add starting inventory to trackers and received items table. (#3051)

commit bb481256de
Author: Aaron Wagener <mmmcheese158@gmail.com>
Date:   Thu Mar 28 21:48:40 2024 -0500

    Core: Make fill failure error more human parseable (#3023)

commit 301d9de975
Author: Aaron Wagener <mmmcheese158@gmail.com>
Date:   Thu Mar 28 19:31:59 2024 -0500

    Docs: adding games rework (#2892)

    * Docs: complete adding games.md rework

    * remove all the now unused images

    * review changes

    * address medic's review

    * address more comments

commit 9dc708978b
Author: Trevor L <80716066+TRPG0@users.noreply.github.com>
Date:   Thu Mar 28 18:26:58 2024 -0600

    Hylics 2: Fix invalid multiworld data, use `self.random` instead of `self.multiworld.random` (#3001)

    * Hylics 2: Fixes

    * Rewrite loop

commit 4391d1f4c1
Author: Bryce Wilson <gyroscope15@gmail.com>
Date:   Thu Mar 28 18:05:39 2024 -0600

    Pokemon Emerald: Fix opponents learning non-randomized TMs (#3025)

commit 5d9d4ed9f1
Author: black-sliver <59490463+black-sliver@users.noreply.github.com>
Date:   Fri Mar 29 01:01:31 2024 +0100

    SoE: update to pyevermizer v0.48.0 (#3050)

commit c97215e0e7
Author: Scipio Wright <scipiowright@gmail.com>
Date:   Thu Mar 28 17:23:37 2024 -0400

    TUNIC: Minor refactor of the vanilla_portals function (#3009)

    * Remove unused, change an if to an elif

    * Remove unused import

commit eb66886a90
Author: Alchav <59858495+Alchav@users.noreply.github.com>
Date:   Thu Mar 28 16:23:01 2024 -0500

    SC2: Don't Filter Excluded Victory Locations (#3018)

commit de860623d1
Author: Fabian Dill <Berserker66@users.noreply.github.com>
Date:   Thu Mar 28 22:21:56 2024 +0100

    Core: differentiate between unknown worlds and broken worlds in error message (#2903)

commit 74b2bf5161
Author: Bryce Wilson <gyroscope15@gmail.com>
Date:   Thu Mar 28 15:20:55 2024 -0600

    Pokemon Emerald: Exclude norman trainer location during norman goal (#3038)

commit 74ac66b032
Author: BadMagic100 <dempsey.sean@outlook.com>
Date:   Thu Mar 28 08:49:19 2024 -0700

    Hollow Knight: 0.4.5 doc revamp and default options tweaks (#2982)

    Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

commit 80d7ac4164
Author: Silvris <58583688+Silvris@users.noreply.github.com>
Date:   Thu Mar 28 09:41:32 2024 -0500

    KDL3: RC1 Fixes and Enhancement (#3022)

    * fix cloudy park 4 rule, zero deathlink message

    * remove redundant door_shuffle bool

    when generic ER gets in, this whole function gets rewritten. So just clean it a little now.

    * properly fix deathlink messages, fix fill error

    * update docs

commit 77311719fa
Author: Ziktofel <ziktofel@gmail.com>
Date:   Thu Mar 28 15:38:34 2024 +0100

    SC2: Fix HERC upgrades (#3044)

commit cfc1541be9
Author: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Date:   Thu Mar 28 15:19:32 2024 +0100

    Docs: Mention the "last received item index" paradigm in the network protocol docs (#2989)

    Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

commit 4d954afd9b
Author: Scipio Wright <scipiowright@gmail.com>
Date:   Thu Mar 28 10:11:20 2024 -0400

    TUNIC: Add link to AP plando guide to connection plando section of game page (#2993)

commit 17748a4bf1
Author: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
Date:   Thu Mar 28 10:00:10 2024 -0400

    Launcher, Docs: Update UI and Set-Up Guide to Reference Options  (#2950)

commit 9182fe563f
Author: Entropynines <163603868+Entropynines@users.noreply.github.com>
Date:   Thu Mar 28 06:56:35 2024 -0700

    README: Remove outdated information about launchers (#2966)

    Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

commit bcf223081f
Author: t3hf1gm3nt <59876300+t3hf1gm3nt@users.noreply.github.com>
Date:   Thu Mar 28 09:54:56 2024 -0400

    TLOZ: Fix markdown issue with game info page (#2985)

commit fa93488f3f
Author: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Date:   Thu Mar 28 09:46:00 2024 -0400

    Docs: Consistent naming for "connection plando" (#2994)

commit db15dd4bde
Author: chandler05 <66492208+chandler05@users.noreply.github.com>
Date:   Thu Mar 28 08:45:19 2024 -0500

    A Short Hike: Fix incorrect info in docs (#3016)

commit 01cdb0d761
Author: PoryGone <98504756+PoryGone@users.noreply.github.com>
Date:   Thu Mar 28 09:44:23 2024 -0400

    SMW: Update World Doc for v2.0 Features (#3034)

    Co-authored-by: Scipio Wright <scipiowright@gmail.com>

commit d0ac2b744e
Author: panicbit <panicbit@users.noreply.github.com>
Date:   Thu Mar 28 10:11:26 2024 +0100

    LADX: fix local and non-local instrument placement (#2987)

    * LADX: fix local and non-local instrument placement

    * change confusing variable name

commit 14f5f0127e
Author: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>
Date:   Thu Mar 28 04:42:35 2024 -0400

    Stardew Valley: Fix potential soft lock with vanilla tools and entrance randomizer + Performance improvement for vanilla tool/skills (#3002)

    * fix vanilla tool fishing rod requiring metal bars
    fix vanilla skill requiring previous level (it's always the same rule or more restrictive)

    * add test to ensure fishing rod need fish shop

    * fishing rod should be indexed from 0 like a mentally sane person would do.

    * fishing rod 0 isn't real, but it definitely can hurt you.

    * reeeeeeeee

commit cf133dde72
Author: Bryce Wilson <gyroscope15@gmail.com>
Date:   Thu Mar 28 02:32:27 2024 -0600

    Pokemon Emerald: Fix typo (#3020)

commit ca18121811
Author: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>
Date:   Thu Mar 28 04:27:49 2024 -0400

    Stardew Valley: Fix generation fail with SVE and entrance rando when Wizard Tower is in place of Sprite Spring (#2970)

commit 1d4512590e
Author: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Date:   Wed Mar 27 21:09:09 2024 +0100

    requirements.txt: _ instead of - to make PyCharm happy (#3043)

commit f7b415dab0
Author: agilbert1412 <alexgilbert@yahoo.com>
Date:   Tue Mar 26 19:40:58 2024 +0300

    Stardew valley: Game version documentation (#2990)

    Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

commit 702f006c84
Author: LiquidCat64 <74896918+LiquidCat64@users.noreply.github.com>
Date:   Tue Mar 26 07:31:36 2024 -0600

    CV64: Change all mentions of "settings" to "options" and fix a broken link (#3015)

commit 98ce8f8844
Author: Yussur Mustafa Oraji <N00byKing@hotmail.de>
Date:   Tue Mar 26 14:29:25 2024 +0100

    sm64ex: New Options API and WebHost fix (#2979)

commit ea47b90367
Author: Scipio Wright <scipiowright@gmail.com>
Date:   Tue Mar 26 09:25:41 2024 -0400

    TUNIC: You can grapple down here without the ladder, neat (#3019)

commit bf3856866c
Author: agilbert1412 <alexgilbert@yahoo.com>
Date:   Sun Mar 24 23:53:49 2024 +0300

    Stardew Valley: presets with some of the new available values for existing settings to make them more accurate (#3014)

commit c0368ae0d4
Author: Phaneros <31861583+MatthewMarinets@users.noreply.github.com>
Date:   Sun Mar 24 13:53:20 2024 -0700

    SC2: Fixed missing upgrade from custom tracker (#3013)

commit 36c83073ad
Author: Salzkorn <salzkitty@gmail.com>
Date:   Sun Mar 24 21:52:41 2024 +0100

    SC2 Tracker: Fix grouped items pointing at wrong item IDs (#2992)

commit 2b24539ea5
Author: Ziktofel <ziktofel@gmail.com>
Date:   Sun Mar 24 21:52:16 2024 +0100

    SC2 Tracker: Use level tinting to let the player know which level he has of Replenishable Magazine (#2986)

commit 7e904a1c78
Author: Ziktofel <ziktofel@gmail.com>
Date:   Sun Mar 24 21:51:46 2024 +0100

    SC2: Fix Kerrigan presence resolving when deciding which races should be used (#2978)

commit bdd498db23
Author: Alchav <59858495+Alchav@users.noreply.github.com>
Date:   Fri Mar 22 15:36:27 2024 -0500

    ALTTP: Fix #2290's crashes (#2973)

commit 355223b8f0
Author: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com>
Date:   Fri Mar 22 15:35:00 2024 -0500

    Yoshi's Island: Implement New Game (#2141)

    Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>
    Co-authored-by: Alchav <59858495+Alchav@users.noreply.github.com>
    Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
    Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

commit aaa3472d5d
Author: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Date:   Fri Mar 22 21:30:51 2024 +0100

    The Witness: Fix seed bleed issue (#3008)

commit 96d93c1ae3
Author: chandler05 <66492208+chandler05@users.noreply.github.com>
Date:   Fri Mar 22 15:30:23 2024 -0500

    A Short Hike: Add option to customize filler coin count (#3004)

    Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

commit ca549df20a
Author: Silvris <58583688+Silvris@users.noreply.github.com>
Date:   Fri Mar 22 15:29:24 2024 -0500

    CommonClient: fix hint tab overlapping (#2957)

    Co-authored-by: Remy Jette <remy@remyjette.com>

commit 44988d430d
Author: Star Rauchenberger <fefferburbia@gmail.com>
Date:   Fri Mar 22 15:28:41 2024 -0500

    Lingo: Add trap weights option (#2837)

commit 11b32f17ab
Author: Danaël V <104455676+ReverM@users.noreply.github.com>
Date:   Fri Mar 22 12:46:14 2024 -0400

    Docs: replacing "setting" to "option" in world docs  (#2622)

    * Update contributing.md

    * Update contributing.md

    * Update contributing.md

    * Update contributing.md

    * Update contributing.md

    * Update contributing.md

    Added non-AP World specific information

    * Update contributing.md

    Fixed broken link

    * Some minor touchups

    * Update Contributing.md

    Draft for version with picture

    * Update contributing.md

    Small word change

    * Minor updates for conciseness, mostly

    * Changed all instances of settings to options in info and setup guides

    I combed through all world docs and swapped "setting" to "option" when this was refering to yaml options.
    I also changed a leftover "setting" in option.py

    * Update contributing.md

    * Update contributing.md

    * Update setup_en.md

    Woops I forgot one

    * Update Options.py

    Reverted changes regarding options.py

    * Update worlds/noita/docs/en_Noita.md

    Co-authored-by: Scipio Wright <scipiowright@gmail.com>

    * Update worlds/sc2wol/docs/en_Starcraft 2 Wings of Liberty.md

    revert change waiting for that page to be updated

    * Update worlds/witness/docs/setup_en.md

    * Update worlds/witness/docs/en_The Witness.md

    * Update worlds/soe/docs/multiworld_en.md

    Fixed Typo

    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

    * Update worlds/witness/docs/en_The Witness.md

    * Update worlds/adventure/docs/en_Adventure.md

    * Update worlds/witness/docs/setup_en.md

    * Updated Stardew valley to hopefully get rid of the merge conflicts

    * Didn't work :dismay:

    * Delete worlds/sc2wol/docs/setup_en.md

    I think this will fix the merge issue

    * Now it should work

    * Woops

    ---------

    Co-authored-by: Scipio Wright <scipiowright@gmail.com>
    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

commit 218cd45844
Author: Silvris <58583688+Silvris@users.noreply.github.com>
Date:   Fri Mar 22 03:02:38 2024 -0500

    APProcedurePatch: fix RLE/COPY incorrect sizing (#3006)

    * change class variables to instance variables

    * Update worlds/Files.py

    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

    * Update worlds/Files.py

    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

    * move required_extensions to tuple

    * fix missing tuple ellipsis

    * fix classvar mixup

    * rename tokens to _tokens. use hasattr

    * type hint cleanup

    * Update Files.py

    * check using isinstance instead

    * Update Files.py

    ---------

    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

commit 4196bde597
Author: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Date:   Thu Mar 21 16:38:36 2024 -0400

    Docs: Fixing special_range_names example (#3005)

commit 40f843f54d
Author: Star Rauchenberger <fefferburbia@gmail.com>
Date:   Thu Mar 21 11:00:53 2024 -0500

    Lingo: Minor game data fixes (#3003)

commit da333fbb0c
Author: GodlFire <46984098+GodlFire@users.noreply.github.com>
Date:   Thu Mar 21 09:52:16 2024 -0600

    Shivers: Adds missing logic rule for skull dial door location (#2997)

commit 43084da23c
Author: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Date:   Thu Mar 21 16:51:29 2024 +0100

    The Witness: Fix newlines in Witness option tooltips (#2971)

commit 14816743fc
Author: Scipio Wright <scipiowright@gmail.com>
Date:   Thu Mar 21 11:50:07 2024 -0400

    TUNIC: Shuffle Ladders option (#2919)

commit 30a0aa2c85
Author: Star Rauchenberger <fefferburbia@gmail.com>
Date:   Thu Mar 21 10:46:53 2024 -0500

    Lingo: Add item/location groups (#2789)

commit f4b7c28a33
Author: Silvris <58583688+Silvris@users.noreply.github.com>
Date:   Wed Mar 20 17:45:32 2024 -0500

    APProcedurePatch: hotfix changing class variables to instance variables (#2996)

    * change class variables to instance variables

    * Update worlds/Files.py

    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

    * Update worlds/Files.py

    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

    * move required_extensions to tuple

    * fix missing tuple ellipsis

    * fix classvar mixup

    * rename tokens to _tokens. use hasattr

    * type hint cleanup

    * Update Files.py

    * check using isinstance instead

    ---------

    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

commit 12864f7b24
Author: chandler05 <66492208+chandler05@users.noreply.github.com>
Date:   Wed Mar 20 22:44:09 2024 +0100

    A Short Hike: Implement New Game (#2577)

commit db02e9d2aa
Author: LiquidCat64 <74896918+LiquidCat64@users.noreply.github.com>
Date:   Wed Mar 20 15:03:25 2024 -0600

    Castlevania 64: Implement New Game (#2472)

commit 32315776ac
Author: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>
Date:   Wed Mar 20 16:57:45 2024 -0400

    Stardew Valley: Fix extended family legendary fishes being locations with fishsanity set to exclude legendary (#2967)

commit e9620bea77
Author: Magnemania <89949176+Magnemania@users.noreply.github.com>
Date:   Wed Mar 20 16:56:00 2024 -0400

    SM64: Goal Logic and Hint Bugfixes (#2886)

commit 183ca35bba
Author: qwint <qwint.42@gmail.com>
Date:   Wed Mar 20 08:39:37 2024 -0500

    CommonClient: Port Casting Bug (#2975)

commit fcaaa197a1
Author: TheLX5 <luisyuregi@gmail.com>
Date:   Wed Mar 20 05:56:19 2024 -0700

    SMW: Fixes for Bowser being defeatable on Egg Hunt and CI2 DC room access (#2981)

commit 8f7b63a787
Author: TheLX5 <luisyuregi@gmail.com>
Date:   Wed Mar 20 05:56:04 2024 -0700

    SMW: Blocksanity logic fixes (#2988)

commit 6f64bb9869
Author: Scipio Wright <scipiowright@gmail.com>
Date:   Wed Mar 20 08:46:31 2024 -0400

    Noita: Remove newline from option description so it doesn't look bad on webhost (#2969)

commit d0a9d0e2d1
Author: Bryce Wilson <gyroscope15@gmail.com>
Date:   Wed Mar 20 06:43:13 2024 -0600

    Pokemon Emerald: Bump required client version (#2963)

commit 94650a02de
Author: Silvris <58583688+Silvris@users.noreply.github.com>
Date:   Tue Mar 19 17:08:29 2024 -0500

    Core: implement APProcedurePatch and APTokenMixin (#2536)

    * initial work on procedure patch

    * more flexibility

    load default procedure for version 5 patches
    add args for procedure
    add default extension for tokens and bsdiff
    allow specifying additional required extensions for generation

    * pushing current changes to go fix tloz bug

    * move tokens into a separate inheritable class

    * forgot the commit to remove token from ProcedurePatch

    * further cleaning from bad commit

    * start on docstrings

    * further work on docstrings and typing

    * improve docstrings

    * fix incorrect docstring

    * cleanup

    * clean defaults and docstring

    * define interface that has only the bare minimum required
    for `Patch.create_rom_file`

    * change to dictionary.get

    * remove unnecessary if statement

    * update to explicitly check for procedure, restore compatible version and manual override

    * Update Files.py

    * remove struct uses

    * ensure returning bytes, add token type checking

    * Apply suggestions from code review

    Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

    * pep8

    ---------

    Co-authored-by: beauxq <beauxq@yahoo.com>
    Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

* Changes pot_completed_list to a instance variable instead of global.

Changes pot_completed_list to a instance variable instead of global. The global variable was unintentional and was causing missmatch in pre_fill which would cause generation error.

* Removing deprecated options getter

* Adds back fix from main branch

Adds back fix from main branch

* Removing messenger changes that somehow got on my branch?

Removing messenger changes that somehow got on my branch?

* Removing messenger changes that are somehow on the Shivers branch

Removing messenger changes that are somehow on the Shivers branch

* Still trying to remove Messenger changes on Shivers branch

Still trying to remove Messenger changes on Shivers branch

* Review comments addressed. Early lobby access set as default.

Review comments addressed. Early lobby access set as default.

* Review comments addressed

Review comments addressed

* Review comments addressed. Option for priority locations removed.

Option to have ixupi captures a priority has been removed and can be added again if Priority Fill is changed. See Issues #3467.

* Minor Change

Minor Change

* Fixed ID 10 T Error

Fixed ID 10 T Error

* Front door option added to slot data

Front door option added to slot data

* Add missing .value on slot data

Add missing .value on slot data

* Small change to slot data

Small change to slot data

* Small change to slot data

Why didn't this change get pushed github...

* Forgot list

Forgot list

---------

Co-authored-by: Kory Dondzila <korydondzila@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Bomb Rush Cyberfunk: Fix Coil quest being in glitched logic too early (#3720)

* Update Rules.py

* Update Rules.py

* Options: Always verify keys for VerifyKeys options (#3280)

* Options: Always verify keys for VerifyKeys options

* fix PlandoTexts

* use OptionError and give a slightly better error message for which option it is

* add the player name to the error

* don't create an unnecessary list

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>

* Docs: Add FFMQ French Setup Guide + Minor fixes to English Guide (#3590)

* Add docs

* Fix character

* Configuration

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* ajuster

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* inclure

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* doublon

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* remplissage

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* autre

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* pouvoir

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* mappemonde

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* apostrophes

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* virgule

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* fournir

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* apostrophes 2

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* snes9x

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* apostrophes 3

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* options

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* lien

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* de laquelle

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* Étape de génération

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* apostrophes 4

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* également

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* guillemets

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* guillemets 2

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* adresse

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* Connect

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* seed

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* Changer fichier yaml pour de configuration

* Fix capitalization

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Fix capitalization 2

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Fix typo+Add link to fr/en info page

---------

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Spire: Convert options, clean up random calls, and add DeathLink (#3704)

* Convert StS options

* probably a bad idea

* Update worlds/spire/Options.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

---------

Co-authored-by: Kono Tyran <Kono@koifysh.dev>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Core: fix missing import for `MultiWorld.link_items()` (#3731)

* Pokemon R/B: Removing Floats from NamedRange #3717

* Docs: Missed Full Accessibility mention/conversion #3734

* ChecksFinder: Refactor/Cleaning (#3725)

* Update ChecksFinder

* minor cleanup

* Check for compatible name

* Enable APWorld

* Update setup_en.md

* Update en_ChecksFinder.md

* The client is getting updated instead

* Qwint suggestions, ' -> ", streamline fill_slot_data

* Oops, too many refactors

---------

Co-authored-by: SunCat <suncat.game@ya.ru>

* OSRS: Implement New Game (#1976)

* MMBN3: Press program now has proper color index when received remotely

* Initial commit of OSRS untangled from MMBN3 branch

* Fixes some broken region connections

* Removes some locations

* Rearranges locations to fill in slots left by removed locations

* Adds starting area rando

* Moves Oak and Willow trees to resource regions

* Fixes various PEP8 violations

* Refactor of regions

* Fixes variable capture issue with region rules

* Partial completion of brutal grind logic

* Finishes can_reach_skill function

* Adds skill requirements to location rules, fixes regions rules

* Adds documentation for OSRS

* Removes match statement

* Updates Data Version to test mode to prevent item name caching

* Fixes starting spawn logic for east varrock

* Fixes river lum crossing logic to not assume you can phase across water

* Prevents equipping items when you haven't unlocked them

* Changes canoe logic to not require huge levels

* Skeletoning out some data I'll need for variable task system

* Adds csvs and parser for logic

* Adds Items parsing

* Fixes the spawning logic to not default to Chunksanity when you didn't pick it

* Begins adding generation rules for data-driven logic

* Moves region handling and location creating to different methods

* Adds logic limits to Options

* Begun the location generation has

* Randomly generates tasks for each skill until populated

* Mopping up improper names, adding custom logic, and fixes location rolling

* Drastically cleans up the location rolling loop

* Modifies generation to properly use local variables and pass unit tests

* Game is now generating, but rules don't seem to work

* Lambda capture, my old nemesis. We meet again

* Fixes issue with Corsair Cove item requirement causing logic loop

* Okay one more fix, another variable capture

* On second thought lets not have skull sceptre tasks. 'Tis a silly place

* Removes QP from item pool (they're events not items)

* Removes Stronghold floor tasks, no varbit to track them

* Loads CSV with pkutil so it can be used in apworld

* Fixes logic of skill tasks and adds QP requirements to long grinds

* Fixes pathing in pkgutil call

* Better handling for empty task categories, no longer throws errors

* Fixes order for progressive tasks, removes un-checkable spider task

* Fixes logic issues related to stew and the Blurite caves

* Fixes issues generating causing tests to sporadically fail

* Adds missing task that caused off-by-one error

* Updates to new Options API

* Updates generation to function properly with the Universal Tracker (Thanks Faris)

* Replaces runtime CSV parsing with pre-made python files generated from CSVs

* Switches to self.random and uses random.choice instead of doing it manually

* Fixes to typing, variable names, iterators, and continue conditions

* Replaces Name classes with Enums

* Fixes parse error on region special rules

* Skill requirements check now returns an accessrule instead of being one that checks options

* Updates documentation and setup guide

* Adjusts maximum numbers for combat and general tasks

* Fixes region names so dictionary lookup works for chunksanity

* Update worlds/osrs/docs/en_Old School Runescape.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update worlds/osrs/docs/en_Old School Runescape.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Updates readme.md and codeowners doc

* Removes erroneous East Varrock -> Al Kharid connection

* Changes to canoe logic to account for woodcutting level options

* Fixes embarassing typo on 'Edgeville'

* Moves Logic CSVs to separate repository, addresses suggested changes on PR

* Fixes logic error in east/west lumbridge regions. Fixes incorrect List typing in main

* Removes task types with weight 0 from the list of rollable tasks

* Missed another place that the task type had to be removed if 0 weight

* Prevents adding an empty task weight if levels are too restrictive for tasks to be added

* Removes giant blank space in error message

* Adds player name to error for not having enough available tasks

---------

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* TUNIC: Fix missing traversal req #3740

* TUNIC: Sort entrances in the spoiler log (#3733)

* Sort entrances in spoiler log

* Rearrange portal list to closer match the vanilla game order, for better spoiler and because I already did this mod-side

* Add break (thanks vi)

* KH2: Update the docs to support steam in the setup guide (#3711)

* doc updates

* add steam link

* Update worlds/kh2/docs/setup_en.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update setup_en.md

* Forgot to include these

* Consistent styling

* :)

* version 3.3.0

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* RoR2: Remove recursion from explore mode access rules (#3681)

The access rules for "<Environment name> Chest n", "<Environment name>
Shrine n" etc. locations recursively called state.can_reach() for the
n-1 location name, with the n=1 location being the only location to have
the actual access rule set.

This patch removes the recursion, instead setting the actual access rule
directly on each location, increasing the performance of checking
accessibility of n>1 locations.

Risk of Rain 2 was already quite fast to generate despite the recursion
in the access rules, but with this patch, generating a multiworld with
200 copies of the template RoR2 yaml (and progression balancing
disabled through a meta.yaml) goes from about 18s to about 6s for me.

From generating the same seed before and after this patch, the same
result is produced.

* Aquaria: Logic bug fixes (#3679)

* Fixing logic bugs

* Require energy attack in the cathedral and energy form in the body

* King Jelly can be beaten easily with only the Dual Form

* I think that I have a problem with my left and right...

* There is a monster that is blocking the path, soo need attack to pass

* The Li cage is not accessible without the Sunken city boss

* Removing useless space.

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Two more minors logic modification

* Adapting tests to af9b6cd

* Reformat the Region file

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* HK: add grub hunt goal (#3203)

* makes grub hunt goal option that calculates the total available grubs (including item link replacements) and requires all of them to be gathered for goal completion

* update slot data name for grub count

* add option to set number needed for grub hub

* updates to grub hunt goal based on review

* copy/paste fix

* account for 'any' goal and fix overriding non-grub goals

* making sure godhome is in logic for any and removing redundancy on completion condition

* fix typing

* i hate typing

* move to stage_pre_fill

* modify "any" goal so all goals are in logic under minimal settings

* rewrite grub counting to create lookups for grubs and groups that can be reused

* use generator instead of list comprehension

* fix whitespace merging wrong

* minor code cleanup

* DS3: Version 3.0.0 (#3128)

* Update worlds/dark_souls_3/Locations.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Fix Covetous Silver Serpent Ring location

* Update location groups

This should cover pretty much all of the seriously hidden items. It
also splits out miniboss drops, mimic drops, and hostile NPC drops.

* Remove the "Guarded by Keys" group

On reflection, I don't think this is actually that useful. It'll also
get a lot muddier once we can randomize shops and ashes become
pseudo-"keys".

* Restore Knight Slayer's Ring classification

* Support infusions/upgrades in the new DS3 mod system

* Support random starting loadouts

* Make an item's NPC status orthogonal to its category

* Track location groups with flags

* Track Archipelago/Offline mismatches on the server

Also fix a few incorrect item names.

* Add additional locations that are now randomizable

* Don't put soul and multiple items in shops

* Add an option to enable whether NG+ items/locations are included

* Clean up useful item categorization

There are so many weapons in the game now, it doesn't make sense to
treat them all as useful

* Add more variety to filler items

* Iron out a few bugs and incompatibilities

* Fix more silly bugs

* Get tests passing

* Update options to cover new item types

Also recategorize some items.

* Verify the default values of `Option`s.

Since `Option.verify()` can handle normalization of option names, this allows options  to define defaults which rely on that normalization. For example, it allows a world to exclude certain locations by default.

This also makes it easier to catch errors if a world author accidentally sets an invalid default.

* Make a few more improvements and fixes

* Randomize Path of the Dragon

* Mark items that unlock checks as useful

These items all unlock missable checks, but they're still good to ahve in the game for variety's sake.

* Guarantee more NPC quests are completable

* Fix a syntax error

* Fix rule definition

* Support enemy randomization

* Support online Yhorm randomization

* Remove a completed TODO

* Fix tests

* Fix force_unique

* Add an option to smooth out upgrade item progression

* Add helpers for setting location/entrance rules

* Support smoother soul item progression

* Fill extra smoothing items into conditional locations as well as other worlds

* Add health item smoothing

* Handle infusions at item generation time

* Handle item upgrades at genreation time

* Fix Grave Warden's Ashes

* Don't overwrite old rules

* Randomize items based on spheres instead of DS3 locations

* Add a smoothing option for weapon upgrades

* Add rules for crow trades

* Small fixes

* Fix a few more bugs

* Fix more bugs

* Try to prevent Path of the Dragon from going somewhere it doesn't work

* Add the ability to provide enemy presets

* Various fixes and features

* Bug fixes

* Better Coiled Sword placement

* Structure DarkSouls3Location more like DarkSouls3Item

* Add events to make DS3's spheres more even

* Restructure locations to work like items do now

* Add rules for more missable locations

* Don't add two Storm Rulers

* Place Hawk Ring in Farron Keep

* Mark the Grass Crest Shield as useful

* Mark new progression items

* Fix a bug

* Support newer better Path of the Dragon code

* Don't lock the player out of Coiled Sword

* Don't create events for missable locations

* Don't throw strings

* Don't smooth event items

* Properly categorize Butcher Knife

* Be more careful about placing Yhorm in low-randomization scenarios

* Don't try to smooth DLC items with DLC disabled

* Fix another Yhorm bug

* Fix upgrade/infusion logic

* Remove the PoolType option

This distinction is no longer meaningful now that every location in
the game of each type is randomized

* Categorize HWL: Red Eye Orb as an NPC location

* Don't place Storm Ruler on CA: Coiled Sword

* Define flatten() locally to make this APWorld capable

* Fix some more Leonhard weirdness

* Fix unique item randomization

* Don't double Twin Dragon Greatshield

* Remove debugging print

* Don't add double Storm Ruler

Also remove now-redundant item sorting by category in create_items.

* Don't add double Storm Ruler

Also remove now-redundant item sorting by category in create_items.

* Add a missing dlc_enabled check

* Use nicer options syntax

* Bump data_version

* Mention where Yhorm is in which world

* Better handle excluded events

* Add a newline to Yhorm location

* Better way of handling excluded unradomized progression locations

* Fix a squidge of nondeterminism

* Only smooth items from this world

* Don't smooth progression weapons

* Remove a location that doesn't actually exist in-game

* Classify Power Within as useful

* Clarify location names

* Fix location requirements

* Clean up randomization options

* Properly name Coiled Sword location

* Add an option for configuring how missable items are handled

* Fix some bugs from location name updates

* Fix location guide link

* Fix a couple locations that were busted offline

* Update detailed location descriptions

* Fix some bugs when generating for a multiworld

* Inject Large Leather Shield

* Fix a few location issues

* Don't allow progression_skip_balancing for unnecessary locs

* Update some location info

* Don't uniquify the wrong items

* Fix some more location issues

* More location fixes

* Use hyphens instead of parens for location descriptions

* Update and fix more locations

* Fix Soul of Cinder boss name

* Fix some logic issues

* Add item groups and document item/location groups

* Fix the display name for "Impatient Mimics"

* Properly handle Transposing Kiln and Pyromancer's Flame

* Testing

* Some fixes to NPC quests, late basin, and transposing kiln

* Improve a couple location names

* Split out and improve missable NPC item logic

* Don't allow crow trades to have foreign items

* Fix a variable capture bug

* Make sure early items are accessible early even with early Castle

* Mark ID giant slave drops as missable

* Make sure late basin means that early items aren't behind it

* Make is_location_available explicitly private

* Add an _add_item_rule utility that checks availability

* Clear excluded items if excluded_locations == "unnecessary"

* Don't allow upgrades/infusions in crow trades

* Fix the documentation for deprecated options

* Create events for all excluded locations

This allows `can_reach` logic to work even if the locations are
randomized.

* Fix up Patches' and Siegward's logic based on some manual testing

* Factor out more sub-methods for setting location rules

* Oops, left these in

* Fixing name

* Left that in too

* Changing to NamedRange to support special_range_names

* Alphabetizing

* Don't call _is_location_available on foreign locations

* Add missing Leonhard items

* Changing late basin to have a post-small-doll option

* Update basin option, add logic for some of Leonhard Hawkwood and Orbeck

* Simplifying an option, fixing a copy-paste error

* Removing trailing whitespace

* Changing lost items to go into start inventory

* Revert Basin changes

* Oops

* Update Options.py

* Reverting small doll changes

* Farron Keep boss requirement logic

* Add Scroll for late_dlc

* Fixing excluded unnecessary locations

* Adding Priestess Ring as being after UG boss

* Removing missable from Corvian Titanite Slab

* Adding KFF Yhorm boss locks

* Screams about Creighton

* Elite Knight Set isn't permanently missable

* Adding Kiln requirement to KFF

* fixing valid_keys and item groups

* Fixing an option-checker

* Throwing unplaceable Storm Ruler into start inventory

* Update locations

* Refactor item injection

* Update setup doc

* Small fixes

* Fix another location name

* Fix injection calculation

* Inject guaranteed items along with progression items

* Mark boss souls as required for access to regions

This allows us to set quest requirements for boss souls and have them
automatically propagated to regions, means we need less machinery for
Yhorm bosses, and allows us to get rid of a few region-transition
events.

* Make sure Sirris's quest can be completed before Pontiff

* Removing unused list

* Changing dict to list

* Removing unused test

* Update __init__.py

* self.multiworld.random -> self.random (#9)

* Fix some miscellaneous location issues

* Rewrite the DS3 intro page/FAQ

* Removing modifying the itempool after fill (#7)

Co-authored-by: Natalie Weizenbaum <nweiz@google.com>

* Small fixes to the setup guide (#10)

Small fixes, adding an example for connecting

* Expanded Late Basin of Vows and Late DLC (#6)

* Add proper requirements for CD: Black Eye Orb

* Fix Aldrich's name

* Document the differences with the 2.x.x branch

* Don't crash if there are more items than locations in smoothing

* Apply suggestions from code review

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Code review

* Fix _replace_with_filler

* Don't use the shared flatten function in SM

* Track local items separately rather than iterating the multiworld

* Various formatting/docs changes suggested by PyCharm (#12)

* Drop deprecated options

* Rename "offline randomizer" to "static randomizer" which is clearer

* Move `enable_*_locations` under removed options.

* Avoid excluded locations for locally-filled items

* Adding Removed options to error (#14)

* Changes for WebHost options display and the options overhaul

* unpack iterators in item list (#13)

* Allow worlds to add options to prebuilt groups

Previously, this crashed because `typing.NamedTuple` fields such as
`group.name` aren't assignable. Now it will only fail for group names
that are actually incorrectly cased, and will fail with a better error
message.

* Style changes, rename exclude behavior options, remove guaranteed items option

* Spacing/Formatting (#18)

* Various Fixes (#19)

* Universally Track Yhorm (#20)

* Account for excluded and missable

* These are behaviors now

* This is singular, apparently

* Oops

* Fleshing out the priority process

* Missable Titanite Lizards and excluded locations (#22)

* Small style/efficiency changes

* Final passthrough fixes (#24)

* Use rich option formatting

* Make the behavior option values actual behaviors (#25)

* Use !=

* Remove unused flatten utility

* Some changes from review (#28)

* Fixing determinism and making smooth faster (#29)

* Style change

* PyCharm and Mypy fixes (#26)

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Change yhorm default (#30)

* Add indirect condition (#27)

* Update worlds/dark_souls_3/docs/locations_en.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Ship all item IDs to the client

This avoids issues where items might get skipped if, for instance,
they're only in the starting inventory.

* Make sure to send AP IDs for infused/upgraded weapons

* Make `RandomEnemyPresetOption` compatible with ArchipelagoMW/Archipelago#3280 (#31)

* Fix cast

* More typing and small fixes (#32)

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: Exempt-Medic <ExemptMedic@Gmail.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>

* Core: Check parent_region.can_reach first in Location.can_reach (#3724)

* Core: Check parent_region.can_reach first in Location.can_reach

The comment about self.access_rule computing faster on average appears
to no longer be correct with the current caching system for region
accessibility, resulting in self.parent_region.can_reach computing
faster on average.

Generation of template yamls for each game that does not require a rom
to generate, generated with `python -O .\Generate.py --seed 1`
(all durations averaged over at 4 or 5 generations):

Full generation with `spoiler: 1` and no progression balancing:
89.9s -> 72.6s
Only output from above case:
2.6s -> 2.2s

Full generation with `spoiler: 3` and no progression balancing:
769.9s -> 627.1s
Only playthrough calculation + paths from above case:
680.5s -> 555.3s

Full generation with `spoiler: 1` with default progression balancing:
123.5s -> 98.3s
Only progression balancing from above case:
11.3s -> 9.6s

* Update BaseClasses.py

* Update BaseClasses.py

* Update BaseClasses.py

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>

* Core: Speed up CollectionState.copy() using built-in copy methods (#3678)

All the types being copied are built-in types with their own `copy()`
methods, so using the `copy` module was a bit overkill and also slower.

This patch replaces the use of the `copy` module in
`CollectionState.copy()` with using the built-in `.copy()` methods.

The copying of `reachable_regions` and `blocked_connections` was also
iterating the keys of each dictionary and then looking up the value in
the dictionary for that key. It is faster, and I think more readable, to
iterate the dictionary's `.items()` instead.

For me, when generating a multiworld including the template yaml of
every world with `python -O .\Generate.py --skip_output`, this patch
saves about 2.1s. The overall generation duration for these yamls varies
quite a lot, but averages around 160s for me, so on average this patch
reduced overall generation duration (excluding output duration) by
around 1.3%.

Timing comparisons were made by calling time.perf_counter() at the start
and end of `CollectionState.copy()`'s body, and summing the differences
between the starts and ends of the method body into a global variable
that was printed at the end of generation.

Additional timing comparisons were made, using the `timeit` module, of
the individual function calls or dictionary comprehensions used to
perform the copying.

The main performance cost was `copy.deepcopy()`, which gets slow as the
number of keys multiplied by the number of values within the
sets/Counters gets large, e.g., to deepcopy a `dict[int, Counter[str]]`
with 100 keys and where each Counter contains 100 keys was 30x slower
than most other tested copying methods. Increasing the number of dict
keys or Counter keys only makes it slower.

* HK: fix iterating all worlds instead of only HK worlds in stage_pre_fill (#3750)

Would cause generation to fail when generating with HK and another game.

Mistake in 6803c373e5.

* DOOM, DOOM II: Update steam URLs (#3746)

* TLOZ: world: multiworld (#3752)

* SoE: fix determinism (#3745)

Fixes randomly placed ingredients not being deterministic (depending on settings)
and in turn also fixes logic not being deterministic if they get replaced by fragments.

* Core: fix invalid __package__ of zipped worlds (#3686)

* fix invalid package fix

* add comment describing fix

* Clique: Update to new options API (#3759)

* Timespinner: Fix eels check logic #3777

* TUNIC: Add note to Universal Tracker stuff #3772

* Core: change start inventory from pool to warn when nothing to remove (#3158)

* makes start inventory from pool warn and fixes the itempool to match when it can not find a matching item to remove

* calc the difference correctly

* save new filler and non-removed items differently so we don't remove existing items at random

* Undertale: Fix slot_data and options.as_dict() (#3774)

* Undertale: Fixing slot_data

* Booleans were difficult

* Core: Error on empty options.as_dict (#3773)

* Error on empty options.as_dict

* ValueError instead

* Apply suggestions from code review

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

---------

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>

* Core: Remove broken unused code from Options.py (#3781)

"Unused" is a baseless assertion, but this code path has been crashing on the first statement for 6 months and noone's complained

* Core: Two Small Fixes (#3782)

* Core: recontextualize `CollectionState.collect` (#3723)

* Core: renamed `CollectionState.collect` arg from `event` to `prevent_sweep` and remove forced collection

* Update TestDungeon.py

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>

* Core: dump all item placements for generation failures. (#3237)

* Core: dump all item placements for generation failures

* pass the multiworld from remaining fill

* change how the args get handled to fix formatting

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>

* Tests: fix the all games multiworld test (#3788)

* TUNIC: Swap from multiworld.get to world.get for applicable things (#3789)

* Swap from multiworld.get to world.get for applicable things

* Why was this even here in the first place?

* I have no idea (#3791)

* TUNIC: Add off and on aliases for the Entrance Rando option #3794

* Stardew Valley: Add Quality Bobber in the logic rules for fish quality gold and above #3792

* Core: Require excluded locations to be reachable with full/locations accessibility (#3802)

* Make excludeds reachable

* Update all_state tests

* Lingo: Fixed Initiated-side Eight Door not opening (#3793)

* TUNIC: Give the fox a gun (in logic) (very small PR) (#3790)

* Add bomb wall logic

* Remove option call from can_shop

* Gun for the envoy blocking Quarry

* has_sword -> can_shop on cube cave entrance region

* TLOZ: Fix non-deterministic item pool generation (#3779)

* TLOZ: Fix non-deterministic item pool generation

The way the item pool was constructed involved iterating unions of sets.
Sets are unordered, so the order of iteration of these combined sets
would be non-deterministic, resulting in the items in the item pool
being generated in a different order with the same seed.

Rather than creating unions of sets at all, the original code has been
replaced with using Counter objects. As a dict subclass, Counter
maintains insertion order, and its update() method makes it simple to
combine the separate item dictionaries into a single dictionary with the
total count of each item across each of the separate item dictionaries.

Fixes #3664 - After investigating more deeply, the only differences I
could find between generations of the same seed was the order of items
created by TLOZ, so this patch appears to fix the non-deterministic
generation issue. I did manage to reproduce the non-deterministic
behaviour with just TLOZ in the end, but it was very rare. I'm not
entirely sure why generating with SMZ3 specifically would cause the
non-deterministic behaviour in TLOZ to be frequently present, whereas
generating with other games or multiple TLOZ yamls would not.

* Change import order

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>

* Docs: Update 'tag' documentation (#3632)

* Add tag docs for HintGame

* Apply suggestions from code review

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

* Make Tracker/TextOnly consistent with previous commit

* Apply suggestion

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

* fix spacing

* Apply suggestion

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

* apply suggestion correcting footnotes

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* [OSRS] Fixes Incorrect filler item names causing failures on tests. (#3768)

* Updates filler item names to match the actual item names

* Adds more descriptive error message in case this error comes back

* Properly raises exception instead of just text

* Replaces exception with assert

* Fix !remaining for cross-world items (#3732)

* Fix !remaining for other worlds

* Typing fixes for the previous change

* Update LocationStore test to match what get_remaining now returns

* Core: early_local != local_early #3780

* Pokemon Emerald: Ensure dig tutor is always usable (#3660)

* Pokemon Emerald: Ensure dig tutor is always usable

* Pokemon Emerald: Clarify comment

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Core: type for `CommonContext.ui` (#3796)

* Core: type for `CommonContext.ui`

* use `Optional`

* VVVVVV: Make unnecessary Trinkets filler (#3806)

* Make unnecessary trinkets filler

* Proper syntax

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Kingdom Hearts: Implement New Game (#3201)

* Added Final Ansem Goal

* Update __init__.py

* Update Rules.py

* New EotW logic

* Update __init__.py

* Update __init__.py

* Update Items.py

* Update Rules.py

* Rename Location to be more meaningful, logic fixes

* Removed Aerith locations

* Change to allow randomized keyblade stats

* Fixed incorrect option description.  Fixed victory locations for alternative win condition settings

* Commit

* Lots of changes

* Fixes

* Fixes

* Update Rules.py

* Update Rules.py

* Update Rules.py

* Update Rules.py

* Fixes

* Update Rules.py

* Update Rules.py

* Update Options.py

* Old Book is not required

* Added Jungle Slider

* Add Cid Check

* Add Wonderland Book Check

* Add OC Green Trinity

* Add Inferno Band Event

* Add Kurt Zisa Zantetsuken and Unknown EXP Necklace checks

* Update Locations.py

* Fix Final Ansem Goal

* Update __init__.py

* Update __init__.py

* Add options to exclude super bosses and 100 acre wood

* Fix puppies trp, remove cid check

* Fix 100 Acre Wood Option

* Material to Empty Bottle

* Fixed rules, location names, etc

* Fix super bosses

* Add item + location groups, level sanity

* Fix location and item group names

* Add Bad Starting Weapons Option

* Logic Error for 100 Acre Wood

* Update Rules.py

* Update __init__.py

* Fixes related to randomized keyblade stats and super bosses

* Credits and Fixes

* Logic fixes, location name group changes

* Update Options.py

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update .gitignore

* Update CODEOWNERS

* Update docs/CODEOWNERS

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Fixed Atlantica item group name

* Update CODEOWNERS

* Update Client.py

* Update Items.py

* Update __init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Fixed report group name

* Fixes for PR

* Update Options.py

* Push changes for making the Final Rest Door appear, few option fixes

* Update Rules.py

* Website formatting, 0 min for reports, option description typo

* Create KH1Client.py

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update Options.py

* Update Options.py

* Update Rules.py

* Update Rules.py

* Update Rules.py

* Add Donald and Goofy Death Link

* Add fight logic for optional bosses

* Update __init__.py

* Update Options.py

* Update worlds/kh1/Options.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update Client.py

* Update kh1_en.md

* Update __init__.py

* Cleaning up for PR

* Update Client.py

* Added event locations for vanilla items

* Add proper location groups and auto hint synth shop items when entering

* so many changes

* Update Rules.py

* fixed oathkeeper and crabclaw logic

* Update Rules.py

* Update Rules.py

* Update Rules.py

* Update Rules.py

* Update en_Kingdom Hearts.md

* Update en_Kingdom Hearts.md

* fixing text

* Update kh1_en.md

* Addition of new key items

* Update Regions.py

* Push for start item from pool test

* Update worlds/kh1/Options.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Document update

* Update Rules.py

* Added starting world range and final rest goal option

* Update kh1_en.md

* Update en_Kingdom Hearts.md

* Update __init__.py

* Update __init__.py

* Clean up options descriptions

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Options.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Client.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Fix grammar in document

* Update __init__.py

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Removed return type

* Update __init__.py

* Update __init__.py

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update __init__.py

* Fix missing i replacement, rework set rules to use "self" instead of a million arguments

* Update KH1Client.py

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

* Reformat rules, fix bug with exp mult, add to readme

* Clean up regions, fix client

* Fix item send prompt

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/test/test_goal.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Items.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Locations.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Regions.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Locations.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Locations.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Items.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Regions.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Regions.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

* Fix so many suggestions

* removed junk in missable locations option

* Update __init__.py

* Change credits order

* Update en_Kingdom Hearts.md

* Standardize punctuation

* Update en_Kingdom Hearts.md

* Update en_Kingdom Hearts.md

* Update Regions.py

* Removed "disclude" options in generation fillers

* Update Rules.py

* Update __init__.py

* Fix cemetery typo

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Add option groups and option presets

* Update worlds/kh1/__init__.py

That's a good idea!

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Presets.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* fixed HB rule and formatting on a line in Items.py

* Fix logic bug with Geppetto's House postcard

* Update Rules.py

* Update Options.py

* Update __init__.py

* Update __init__.py

* Huge under-the-hood update for PR

* More updates for PR

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update __init__.py

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Core: Fix incorrect default state checked in MultiWorld.can_beat_game (#3813)

`MultiWorld.can_beat_game()` with no arguments would initially check if
`self.state` is beatable, but then would create an empty state,
`state = CollectionState(self)`, to sweep spheres from to determine if
the game is beatable. The issue was that `self.state` and the new empty
state could be different.

Currently, it seems that everywhere in Archipelago's codebase that calls
`MultiWorld.can_beat_game()` with no arguments or `starting_state=None`
has a `self.state` that only contains precollected items, so the new
empty state happens to result in an equivalent state, but this should
not be relied upon to always be the case.

This patch changes `can_beat_game()` to initially check if the new empty
state is beatable instead of `self.state`.

This appears to be a bug introduced way back in 27b6dd8bd7

Fixes #3742

* The Witness: Fix Tunnels Theater Flower EP Access Logic + Add Unit Test for it (and Expert PP2) (#3807)

* Tunnels Theater Flowers fix + Flowers&PP2 Unit Tests

* copypaste

* Can just do it like this

* This is even better probably

* Also do some cleanup :3

* God damnit

* Docs: `NetworkItem.player` (#3811)

* Docs: `NetworkItem.player`

In many contexts, it's difficult to tell whether this is the sending player or the receiving player.

* correct player info

* Update NetUtils.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

---------

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* Minecraft: Update to new options system. (#3765)

* Move to new options system.
switch to using self.random
reformat rules file.

* further reformats

* fix tests to use new options system.

* fix slot data to not use self.multiworld

* I hate python

* new starting_items docstring to prepare for 1.20.5+ item components.
fix invalid json being output to starting_items

* more typing fixes.

* stupid quotes around type declarations

* removed unused variable in ItemPool.py
change null check in Structures.py

* update rules "self" variable to a "world: MinecraftWorld" variable

* get key, and not value for required bosses.

* The Witness: Panel Hunt Mode (#3265)

* Add panel hunt options

* Make sure all panels are either solvable or disabled in panel hunt

* Pick huntable panels

* Discards in disable non randomized

* Set up panel hunt requirement

* Panel hunt functional

* Make it so an event can have multiple names

* Panel hunt with events

* Add hunt entities to slot data

* ruff

* add to hint data, no client sneding yet

* encode panel hunt amount in compact hint data

* Remove print statement

* my b

* consistent

* meh

* additions for lcient

* Nah

* Victory panels ineligible for panel hunt

* Panel Hunt Postgame option

* cleanup

* Add data generation file

* pull out set

* always disable gate ep in panel hunt

* Disallow certain challenge panels from being panel hunt panels

* Make panelhuntpostgame its own function, so it can be called even if normal postgame is enabled

* disallow PP resets from panel hunt

* Disable challenge timer and elevetor start respectively in disable hunt postgame

* Fix panelhunt postgame

* lol

* When you test that the bug is fixed but not that the non-bug is not unfixed

* Prevent Obelisks from being panel hunt panels

* Make picking panels for panel hunt a bit more sophisticated, if less random

* Better function maybe ig

* Ok maybe that was a bit too much

* Give advanced players some control over panel hunt

* lint

* correct the logic for amount to pick

* decided the jingle thing was dumb, I'll figure sth out client side. Same area discouragement is now a configurable factor, and the logic has been significantly rewritten

* comment

* Make the option visible

* Safety

* Change assert slightly

* We do a little logging

* number tweak & we do a lil logging

* we do a little more logging

* Ruff

* Panel Hunt Option Group

* Idk how that got here

* Update worlds/witness/options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/witness/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* remove merge error

* Update worlds/witness/player_logic.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* True

* Don't have underwater sliding bridge when you have above water sliding bridge

* These are not actually connected lol

* get rid of unnecessary variable

* Refactor compact hint function again

* lint

* Pull out Entity Hunt Picking into its own class, split it into many functions. Kept a lot of the comments tho

* forgot to actually add the new file

* some more refactoring & docstrings

* consistent naming

* flip elif change

* Comment about naming

* Make static eligible panels a constant I can refer back to

* slight formatting change

* pull out options-based eligibility into its own function

* better text and stuff

* lint

* this is not necessary

* capitalisation

* Fix same area discouragement 0

* Simplify data file generation

* Simplify data file generation

* prevent div 0

* Add Vault Boxes -> Vault Panels to replacements

* Update options.py

* Update worlds/witness/entity_hunt.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update entity_hunt.py

* Fix some events not working

* assert

* remove now unused function

* lint

* Lasers Activate, Lasers don't Solve

* lint

* oops

* mypy

* lint

* Add simple panel hunt unit test

* Add Panel Hunt Tests

* Add more Panel Hunt Tests

* Disallow Box Short for normal panel hunt

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* The Witness: Add "vague" hints making use of other games' region names and location groups (#2921)

* Vague hints work! But, the client will probably reveal some of the info through scouts atm

* Fall back on Everywhere if necessary

* Some of these failsafes are not necessary now

* Limit region size to 100 as well

* Actually... like this.

* Nutmeg

* Lol

* -1 for own player but don't scout

* Still make always/priority ITEM hints

* fix

* uwu notices your bug

* The hints should, like, actually work, you know?

* Make it a Toggle

* Update worlds/witness/hints.py

Co-authored-by: Bryce Wilson <gyroscope15@gmail.com>

* Update worlds/witness/hints.py

Co-authored-by: Bryce Wilson <gyroscope15@gmail.com>

* Make some suggested changes

* Make that ungodly equation a bit clearer in terms of formatting

* make that not sorted

* Add a warning about the feature in the option tooltip

* Make using region names experimental

* reword option tooltip

* Note about singleplayer

* Slight rewording again

* Reorder the order of priority a bit

* this condition is unnecessary now

* comment

* No wait the order has to be like this

* Okay now I think it's correct

* Another comment

* Align option tooltip with new behavior

* slight rewording again

* reword reword reword reword

* -

* ethics

* Update worlds/witness/options.py

Co-authored-by: Bryce Wilson <gyroscope15@gmail.com>

* Rename and slight behavior change for local hints

* I think I overengineered this system before. Make it more consistent and clear now

* oops I used checks by accident

* oops

* OMEGA OOPS

* Accidentally commited a print statemetn

* Vi don't commit nonsense challenge difficulty impossible

* This isn't always true but it's good enough

* Update options.py

* Update worlds/witness/options.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Scipio :3

* switch to is_event instead of checking against location.address

* oop

* Update test_roll_other_options.py

* Fix that unit test problem lol

* Oh is this not fixed in the apworld?

---------

Co-authored-by: Bryce Wilson <gyroscope15@gmail.com>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Mega Man 2: Implement New Game (#3256)

* initial (broken) commit

* small work on init

* Update Items.py

* beginning work, some rom patches

* commit progress from bh branch

* deathlink, fix soft-reset kill, e-tank loss

* begin work on targeting new bhclient

* write font

* definitely didn't forget to add the other two hashes no

* update to modern options, begin colors

* fix 6th letter bug

* palette shuffle + logic rewrite

* fix a bunch of pointers

* fix color changes, deathlink, and add wily 5 req

* adjust weapon weakness generation

* Update Rules.py

* attempt wily 5 softlock fix

* add explicit test for rbm weaknesses

* fix difficulty and hard reset

* fix connect deathlink and off by one item color

* fix atomic fire again

* de-jank deathlink

* rewrite wily5 rule

* fix rare solo-gen fill issue, hopefully

* Update Client.py

* fix wily 5 requirements

* undo fill hook

* fix picopico-kun rules

* for real this time

* update minimum damage requirement

* begin move to procedure patch

* finish move to APPP, allow rando boobeam, color updates

* fix color bug, UT support?

* what do you mean I forgot the procedure

* fix UT?

* plando weakness and fixes

* sfx when item received, more time stopper edge cases

* Update test_weakness.py

* fix rules and color bug

* fix color bug, support reduced flashing

* major world overhaul

* Update Locations.py

* fix first found bugs

* mypy cleanup

* headerless roms

* Update Rom.py

* further cleanup

* work on energylink

* el fixes

* update to energylink 2.0 packet

* energylink balancing

* potentially break other clients, more balancing

* Update Items.py

* remove startup change from basepatch

we write that in patch, since we also need to clean the area before applying

* el balancing and feedback

* hopefully less test failures?

* implement world version check

* add weapon/health option

* Update Rom.py

* x/x2

* specials

* Update Color.py

* Update Options.py

* finally apply location groups

* bump minor version number instead

* fix duplicate stage sends

* validate wily 5, tests

* see if renaming fixes

* add shuffled weakness

* remove passwords

* refresh rbm select, fix wily 5 validation

* forgot we can't check 0

* oops I broke the basepatch (remove failing test later)

* fix solo gen fill error?

* fix webhost patch recognition

* fix imports, basepatch

* move to flexibility metric for boss validation

* special case boobeam trap

* block strobe on stage select init

* more energylink balancing

* bump world version

* wily HP inaccurate in validation

* fix validation edge case

* save last completed wily to data storage

* mypy and pep8 cleanup

* fix file browse validation

* fix test failure, add enemy weakness

* remove test seed

* update enemy damage

* inno setup

* Update en_Mega Man 2.md

* setup guide

* Update en_Mega Man 2.md

* finish plando weakness section

* starting rbm edge case

* remove * imports

* properly wrap later weakness additions in regen playthrough

* fix import

* forgot readme

* remove time stopper special casing

since we moved to proper wily 5 validation, this special casing is no longer important

* properly type added locations

* Update CODEOWNERS

* add animation reduction

* deprioritize Time Stopper in rush checks

* special case wily phase 1

* fix key error

* forgot the test

* music and general cleanup

* the great rename

* fix import

* thanks pycharm

* reorder palette shuffle

* account for alien on shuffled weakness

* apply suggestions

* fix seedbleed

* fix invalid buster passthrough

* fix weakness landing beneath required amount

* fix failsafe

* finish music

* fix Time Stopper on Flash/Alien

* asar pls

* Apply suggestions from code review

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* world helpers

* init cleanup

* apostrophes

* clearer wording

* mypy and cleanup

* options doc cleanup

* Update rom.py

* rules cleanup

* Update __init__.py

* Update __init__.py

* move to defaultdict

* cleanup world helpers

* Update __init__.py

* remove unnecessary line from fill hook

* forgot the other one

* apply code review

* remove collect

* Update rules.py

* forgot another

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Blasphemous: Total overhaul (#3355)

* Blasphemous: WIP overhaul

* Entrance rule mistake

* stuff

* Getting closer

* Real?? Maybe??

* Don't fail me now 🙏

* Add starting location tests

* More tests (it still doesn't work actually 😔)

* REAL

* Add unreachable regions to test_reachability.py

* PR ready

- Remove unused functions from init
- Use group exclusive functions in rules
- Style changes

* Bump required client version

* Clean up unused imports

* Change slot data

* Review fixes

- Prevent strength calculations from including excess items
- Add new lines to ends of files
- Fix missed deprecated option and random usage in init

* Update option docstrings, add groups

* Add preprocessor files

* Update option docstrings again actually

* Update player strength calculation

* Rename group methods

* Fix missing logic for RESCUED_CHERUB_06

* Register indirect conditions

* Register indirect conditions (part 2)

* Update extracted logic, change slot data key

* Add region to excluded list

* A capital letter

* Use camelCase keys in preprocessor

* Write some of new setup guide

* Remove indents before list points

* Change locationinfo to list of dictonaries

* Finish docs, update extractor config and data

* Mark region_data.py as generated

* Suggested changes

* More suggested changes

* Suggested changes again

- Use OptionError
- Create list of disabled locations before looping
- Check if options are equal to str instead of int
- Clean up start location override
- Reword some of setup guide
- Organize location list
- Remove unnecessary escaped quotes from option docstrings
- Add world type to test base

* C# moment

* Requested changes

* Update .gitattributes

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>

* MM2: fix Wily 5 Time Stopper rule (#3824)

* fix time stopper rule

* that was the entirely wrong rule actually

* YachtDice: implement new game (#3482)

* Add the yacht dice (from other git) world to the yacht dice fork

* Update .gitignore

* Removed zillion because it doesn't work

* Update .gitignore

* added zillion again...

* Now you can have 0 extra fragments

* Added alt categories, also options

* Added item categories

* Extra categories are now working! 🐶

* changed options and added exceptions

* Testing if I change the generate.py

* Revert "Testing if I change the generate.py"

This reverts commit 7c2b3df6170dcf8d8f36a1de9fcbc9dccdec81f8.

* ignore gitignore

* Delete .gitignore

* Update .gitignore

* Update .gitignore

* Update logic, added multiplicative categories

* Changed difficulties

* Update offline mode so that it works again

* Adjusted difficulty

* New version of the apworld, with 1000 as final score, always

Will still need to check difficulty and weights of adding items.
Website is not ready yet, so this version is not usable yet :)

* Changed yaml and small bug fixes

Fix when goal and max are same
Options: changed chance to weight

* no changes, just whitespaces

* changed how logic works

Now you put an array of mults and the cpu gets a couple of tries

* Changed logic, tweaked a bit too

* Preparation for 2.0

* logic tweak

* Logic for alt categories properly now

* Update setup_en.md

* Update en_YachtDice.md

* Improve performance of add_distributions

* Formatting style

* restore gitignore to APMW

* Tweaked generation parameters and methods

* Version 2.0.3

manual input option
max score in logic always 2.0.3
faster gen

* Comments and editing

* Renamed setup guide

* Improved create_items code

* init of locations: remove self.event line

* Moved setting early items to generate_early

* Add my name to CODEOWNERS

* Added Yacht Dice to the readme in list of games

* Improve performance of Yacht Dice

* newline

* Improve typing

* This is actually just slower lol

* Update worlds/yachtdice/Items.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update Options.py

* Styling

* finished text whichstory option

* removed roll and rollfragments; not used

* import; worlds not world :)

* Option groups!

* ruff styling, fix

* ruff format styling!

* styling and capitalization of options

* small comment

* Cleaned up the "state_is_a_list" a little bit

* RUFF 🐶

* Changed filling the itempool for efficiency

Now, we start with 17 extra items in the item pool, it's quite likely you need at least 17 items (~80%?).
And then afterwards, we delete items if we overshoot the target of 1000, and add items if we haven't reached an achievable score of 1000 yet. Also, no need to recompute the entire logic when adding points.

* 🐶

* Removed plando "fix"

* Changed indent of score multiplier

* faster location function

* Comments to docstrings

* fixed making location closest to goal_score be goal_score

* options format

* iterate keys and values of a dict together

* small optimization ListState

* faster collection of categories

* return arguments instead of making a list (will 🐶 later)

* Instead of turning it into a tuple, you can just make a tuple literal

* remove .keys()

* change .random and used enumerate

* some readability improvements

* Remove location "0", we don't use that one

* Remove lookup_id_to_name entirely

I for sure don't use it, and as far as I know it's not one of the mandatory functions for AP, these are item_name_to_id and location_name_to_id.

* .append instead of += for single items, percentile function changed

Also an extra comment for location ids.

* remove ) too many

* Removed sorted from category list

* Hash categories (which makes it slower :( )

Maybe I messed up or misunderstood...
I'll revert this right away since it is 2x slower, probably because of sorted instead of sort?

* Revert "Hash categories (which makes it slower :( )"

This reverts commit 34f2c1aed8c8813b2d9c58896650b82a810d3578.

* temporary push: 40% faster generation test

Small changes in logic make the generation 40% faster.
I'll have to think about how big the changes are. I suspect they are rather limited.
If this is the way to go, I'll remove the temp file and redo the YachtWeights file, I'll remove the functions there and just put the new weights here.

* Add Points item category

* Reverse changes of bad idea :)

* ruff 🐶

* Use numpy and pmf function to speed up gen

Numpy has a built-in way to sum probability mass functions (pmf).
This shaves of 60% of the generation time :D

* Revert "Use numpy and pmf function to speed up gen"

This reverts commit 9290191cb323ae92321d6c2cfcfe8c27370f439b.

* Step inbetween to change the weights

* Changed the weights to make it faster

135 -> 81 seconds on 100 random yamls

* Adjusted max_dist, split dice_simulation function

* Removed nonlocal and pass arguments instead

* Change "weight-lists" to Dict[str, float]

* Removed the return from ini_locations.

Also added explanations to cat_weights

* Choice options; dont'use .value (will ruff later)

* Only put important options in slotdata

* 🐶

* Add Dict import

* Split the cache per player, limit size to 400.

* 🐶

* added , because of style

* Update apworld version to 2.0.6

2.0.5 is the apworld I released on github to be tested
I never separately released 2.0.4.

* Multiple smaller code improvements

- changed names in YachtWeights so we don't need to translate them in Rules anymore
- we now remember which categories are present in the game, and also put this in slotdata. This we do because only one of two categories is present in a game. If for some reason both are present (plando/getitem/startinventory), we now know which category to ignore
-

* 🐶 ruff

* Mostly minimize_extra_items improvements

- Change logic, generation is now even faster (0.6s per default yaml).
- Made the option 'minimize_extra_items' do a lot more, hopefully this makes the impact of Yacht Dice a little bit less, if you want that. Here's what is also does now:
 - you start with 2 dice and 2 rolls
 - there will be less locations/items at the start of you game

* ruff 🐶

* Removed printing options

* Reworded some option descriptions

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Yacht Dice: setup: change release-link to latest (#3827)

On the installation page, link to the latest release, instead of the page with all releases

* ALTTP: Minor Tweaks to the Adjuster UI (#2533)

* Tweak ALTTP Adjuster padding/size to accommodate resizing

  - Set minsize so the actions buttons on bottom are always visible.
  - Added a minor amount of padding around the top level objects.
  - Increased the size of the entry fields for roms to match general
    button size.
  - Updated layout calls so vertical spacing doesn't increase
    between fields when maximizing the window
  - Added a little bit of spacing on the rom label so it more closely
    lines up with the other rom selection field

* Tweak ALTTP Adjuster padding/size to accommodate resizing

  - Set minsize so the actions buttons on bottom are always visible.
  - Added a minor amount of padding around the top level objects.
  - Increased the size of the entry fields for roms to match general
    button size.
  - Updated layout calls so vertical spacing doesn't increase
    between fields when maximizing the window
  - Added a little bit of spacing on the rom label so it more closely
    lines up with the other rom selection field

* LTTP: Fix a bug in Triforce Pieces Mode: Extra (#3784)

When triforce_pieces_mode is set to "extra", the number of Triforce pieces in the pool should be equal to the number required plus the number extra. The number available was being used in this calculation, instead of the number required.

* The Witness: Ban Excluded Panels from Panel Hunt (#3818)

* excluded panels should not be picked by panel hunt

* ban excluded panels from panel hunt

* Get rid of an unused variable

* Purge the world: multiworld evil from osrs (#3751)

* Core, some worlds: Rename sweep_for_events to sweep_for_advancements (#3571)

* Rename sweep_for_events to sweep_for_advancements

* more event->advancement renames

* oops accidentally deleted the deprecation thing in the force push

* Update TestDungeon.py

* Update BaseClasses.py

* Update BaseClasses.py

* oops

* utils.deprecate

* treble, you had no idea how right you were

* Update test_panel_hunt.py

* Update BaseClasses.py

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>

---------

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>

* Core: some typing and cleaning in `BaseClasses.py` (#3391)

* Core: some typing and cleaning in `BaseClasses.py`

* more backwards `__repr__`

* double-quote string

* remove some end-of-line whitespace

* Celeste 64: Typo #3840

oops

* Kingdom Hearts: Make Ceiling Division Human-Readable #3839

* The Witness: Shuffle Dog (#3425)

* Town Pet the Dog

* Add shuffle dog to options presets

* I cri evritim

* I guess it's as good a time as any

* :(

* fix the soft conflict

* add all the shuffle dog options to some of the unit tests bc why not

* Laser Panels are just 'General' now, I'm pretty sure

* Could I really call it allsanity?

* The Witness: Switch to world.player_name (#3693)

* lint

* player_name

* oops lmao

* shorten

* Launcher: Update message that displays when installing a custom apworld for a game in main (#3607)

* kvui: assert kivy is not imported before kvui (#3823)

* Pokemon Emerald: Send current map to trackers (#3726)

---------

Co-authored-by: Alchav <59858495+Alchav@users.noreply.github.com>
Co-authored-by: alchav <alchav@jalchavware.com>
Co-authored-by: Phaneros <31861583+MatthewMarinets@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: Remy Jette <remy@remyjette.com>
Co-authored-by: Jarno <jarnowesthof@gmail.com>
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Co-authored-by: GodlFire <46984098+GodlFire@users.noreply.github.com>
Co-authored-by: Kory Dondzila <korydondzila@gmail.com>
Co-authored-by: Trevor L <80716066+TRPG0@users.noreply.github.com>
Co-authored-by: wildham <64616385+wildham0@users.noreply.github.com>
Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
Co-authored-by: Kono Tyran <Kono@koifysh.dev>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: SunCat <suncat.game@ya.ru>
Co-authored-by: digiholic <digikun@gmail.com>
Co-authored-by: JaredWeakStrike <96694163+JaredWeakStrike@users.noreply.github.com>
Co-authored-by: Mysteryem <Mysteryem@users.noreply.github.com>
Co-authored-by: Louis M <prog@tioui.com>
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: Natalie Weizenbaum <nweiz@google.com>
Co-authored-by: Exempt-Medic <ExemptMedic@Gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: Kaito Sinclaire <ks@rosenthalcastle.org>
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>
Co-authored-by: Star Rauchenberger <fefferburbia@gmail.com>
Co-authored-by: Emily <35015090+EmilyV99@users.noreply.github.com>
Co-authored-by: Bryce Wilson <gyroscope15@gmail.com>
Co-authored-by: Scrungip <95324612+Scrungip@users.noreply.github.com>
Co-authored-by: gaithern <36639398+gaithern@users.noreply.github.com>
Co-authored-by: KonoTyran <Kono.Tyran@gmail.com>
Co-authored-by: Spineraks <markvanderboor@hotmail.com>
Co-authored-by: B1t <christopher.j.wallis@gmail.com>
Co-authored-by: Kappatechy <jmdewar@shaw.ca>
Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
Co-authored-by: PoryGone <98504756+PoryGone@users.noreply.github.com>
2024-08-29 08:41:57 +02:00
Scipio Wright 0e55ddc7cf
LADX: Filter braces out of player names for hint text (#3831)
* Filter braces out of player names for hint text

* Filter out another spot
2024-08-29 08:15:49 +02:00
Bryce Wilson ab5b986716
Pokemon Emerald: Move magma grunt (#3836) 2024-08-29 08:14:08 +02:00
Emily 97c313c1c4
APSudoku: Update setup guide, remove extraneous options page link (#3849)
* APSudoku: Update setup guide, remove extraneous options page link

* Apply suggestions from code review

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* clean up instructions

* IP -> address

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-29 08:12:58 +02:00
Mysteryem 701a7faa71
AHIT: Fix Time Rift - Alpine Skyline entrance logic (#3851)
The `Time Rift - Alpine Skyline` region was incorrectly accessible from
Alpine Free Roam without Hookshot Badge or Umbrella.

One of the two regions that connects to the `Time Rift - Alpine Skyline`
region is `Alpine Free Roam`. The problem here is that
`Alpine Free Roam` corresponds to the intro section of Alpine Free Roam,
but the Time Rift is actually found in-game in what equates to the
`Alpine Skyline Area` region.

The entrance connecting `Alpine Free Roam` to `Alpine Skyline Area`
(`AFR -> Alpine Skyline Area`) requires the Hookshot Badge (and Umbrella
if umbrella logic is enabled), but because the entrance to
`Time Rift - Alpine Skyline` is placed in `Alpine Free Roam` instead, it
was missing the hookshot/umbrella requirements.

The missing Hookshot Badge and Umbrella requirements have been added to
`Rules.set_rift_rules()` and `Rules.set_default_rift_rules()`.

The entrances to the `Time Rift - Curly Tail Trail` and `Time Rift - The
Twilight Bell` regions are also in the `Alpine Free Roam` region, but
the logic for both of those entrances require event items that are only
accessible from the `Alpine Skyline Area` region.
2024-08-29 08:11:42 +02:00
Mysteryem 9a4e84efdc
AHIT: Fix moderate logic rules using add_rule instead of set_rule (#3850)
The moderate logic for the Mafia Town Clock Tower Chest and Top of
Ruined Tower with nothing, and for clearing Rock the Boat without Ice
Hat were mistakenly using `add_rule` instead of `set_rule`, which was
adding the condition of `and True` which had no effect.

This patch corrects these moderate logic rules to use `set_rule`
instead.
2024-08-29 08:11:02 +02:00
NewSoupVi 906b23088c
The Witness: Rules Optimisation (#3617)
* Attempt at optimizing rules

* docstrings

* Python 3.8

* Lasers optimisation

* Simplify conversion code and make it even faster

* mypy

* ruff

* Neat

* Add redirect to the other two modes

* Update WitnessLogic.txt

* Update WitnessLogicExpert.txt

* Update WitnessLogicVanilla.txt

* Use NamedTuple

* Ruff

* mypy thing

* Mypy stuff

* Move Redirect Event to Desert Region so it has a better name
2024-08-28 18:31:49 +02:00
Bryce Wilson 0fb69dce33
Pokemon Emerald: Fix map update sending to all trackers (#3846) 2024-08-25 04:08:27 +02:00
Justus Lind e99f027b42
Muse Dash: Update to 4.7.0 - Let's Rhythm Jam! (#3837)
* Update to Muse Dash 4.7.0 Muse Dash - Let's Rhythm Jam!

* Add the replaced song to the removed list.

* Oops add the other secret song to this list.

* Add trailing comma

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2024-08-24 18:19:42 +02:00
Aaron Wagener dddffa1660
LTTP: fix own_dungeon setting from not being placed in the player's own world (#3816) 2024-08-24 10:54:33 +02:00
Exempt-Medic 83367c6946
ALttP: Fix accessibility (locations -> full) (#3801) 2024-08-24 10:53:56 +02:00
Silvris 0fcca25870
Core: deepcopy plando items #3841 2024-08-24 05:41:00 +02:00
Bryce Wilson d1a7fd7da1
Pokemon Emerald: Send current map to trackers (#3726) 2024-08-24 02:51:52 +02:00
qwint 5c5f2ffc94
kvui: assert kivy is not imported before kvui (#3823) 2024-08-24 02:12:01 +02:00
Scipio Wright 6f617e302d
Launcher: Update message that displays when installing a custom apworld for a game in main (#3607) 2024-08-24 02:09:50 +02:00
NewSoupVi 35c9061c9c
The Witness: Switch to world.player_name (#3693)
* lint

* player_name

* oops lmao

* shorten
2024-08-24 02:08:46 +02:00
NewSoupVi e61d521ba8
The Witness: Shuffle Dog (#3425)
* Town Pet the Dog

* Add shuffle dog to options presets

* I cri evritim

* I guess it's as good a time as any

* :(

* fix the soft conflict

* add all the shuffle dog options to some of the unit tests bc why not

* Laser Panels are just 'General' now, I'm pretty sure

* Could I really call it allsanity?
2024-08-24 02:08:04 +02:00
gaithern 6efa065867
Kingdom Hearts: Make Ceiling Division Human-Readable #3839 2024-08-24 02:06:08 +02:00
PoryGone 56dbba6a31
Celeste 64: Typo #3840
oops
2024-08-24 02:05:42 +02:00
Doug Hoskisson 43cb9611fb
Core: some typing and cleaning in `BaseClasses.py` (#3391)
* Core: some typing and cleaning in `BaseClasses.py`

* more backwards `__repr__`

* double-quote string

* remove some end-of-line whitespace
2024-08-24 02:05:30 +02:00
NewSoupVi 64b654d42e
Core, some worlds: Rename sweep_for_events to sweep_for_advancements (#3571)
* Rename sweep_for_events to sweep_for_advancements

* more event->advancement renames

* oops accidentally deleted the deprecation thing in the force push

* Update TestDungeon.py

* Update BaseClasses.py

* Update BaseClasses.py

* oops

* utils.deprecate

* treble, you had no idea how right you were

* Update test_panel_hunt.py

* Update BaseClasses.py

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>

---------

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2024-08-23 01:15:05 +02:00
NewSoupVi 74aab81f79
Purge the world: multiworld evil from osrs (#3751) 2024-08-23 00:23:22 +02:00
NewSoupVi f390b33c17
The Witness: Ban Excluded Panels from Panel Hunt (#3818)
* excluded panels should not be picked by panel hunt

* ban excluded panels from panel hunt

* Get rid of an unused variable
2024-08-23 00:23:05 +02:00
Kappatechy 31852801c9
LTTP: Fix a bug in Triforce Pieces Mode: Extra (#3784)
When triforce_pieces_mode is set to "extra", the number of Triforce pieces in the pool should be equal to the number required plus the number extra. The number available was being used in this calculation, instead of the number required.
2024-08-22 23:35:29 +02:00
B1t e35addf5b2
ALTTP: Minor Tweaks to the Adjuster UI (#2533)
* Tweak ALTTP Adjuster padding/size to accommodate resizing

  - Set minsize so the actions buttons on bottom are always visible.
  - Added a minor amount of padding around the top level objects.
  - Increased the size of the entry fields for roms to match general
    button size.
  - Updated layout calls so vertical spacing doesn't increase
    between fields when maximizing the window
  - Added a little bit of spacing on the rom label so it more closely
    lines up with the other rom selection field

* Tweak ALTTP Adjuster padding/size to accommodate resizing

  - Set minsize so the actions buttons on bottom are always visible.
  - Added a minor amount of padding around the top level objects.
  - Increased the size of the entry fields for roms to match general
    button size.
  - Updated layout calls so vertical spacing doesn't increase
    between fields when maximizing the window
  - Added a little bit of spacing on the rom label so it more closely
    lines up with the other rom selection field
2024-08-22 19:59:11 +02:00
Spineraks 3cdcb8c455
Yacht Dice: setup: change release-link to latest (#3827)
On the installation page, link to the latest release, instead of the page with all releases
2024-08-21 21:40:40 +02:00
Spineraks 48c6a6fb4c
YachtDice: implement new game (#3482)
* Add the yacht dice (from other git) world to the yacht dice fork

* Update .gitignore

* Removed zillion because it doesn't work

* Update .gitignore

* added zillion again...

* Now you can have 0 extra fragments

* Added alt categories, also options

* Added item categories

* Extra categories are now working! 🐶

* changed options and added exceptions

* Testing if I change the generate.py

* Revert "Testing if I change the generate.py"

This reverts commit 7c2b3df6170dcf8d8f36a1de9fcbc9dccdec81f8.

* ignore gitignore

* Delete .gitignore

* Update .gitignore

* Update .gitignore

* Update logic, added multiplicative categories

* Changed difficulties

* Update offline mode so that it works again

* Adjusted difficulty

* New version of the apworld, with 1000 as final score, always

Will still need to check difficulty and weights of adding items.
Website is not ready yet, so this version is not usable yet :)

* Changed yaml and small bug fixes

Fix when goal and max are same
Options: changed chance to weight

* no changes, just whitespaces

* changed how logic works

Now you put an array of mults and the cpu gets a couple of tries

* Changed logic, tweaked a bit too

* Preparation for 2.0

* logic tweak

* Logic for alt categories properly now

* Update setup_en.md

* Update en_YachtDice.md

* Improve performance of add_distributions

* Formatting style

* restore gitignore to APMW

* Tweaked generation parameters and methods

* Version 2.0.3

manual input option
max score in logic always 2.0.3
faster gen

* Comments and editing

* Renamed setup guide

* Improved create_items code

* init of locations: remove self.event line

* Moved setting early items to generate_early

* Add my name to CODEOWNERS

* Added Yacht Dice to the readme in list of games

* Improve performance of Yacht Dice

* newline

* Improve typing

* This is actually just slower lol

* Update worlds/yachtdice/Items.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update Options.py

* Styling

* finished text whichstory option

* removed roll and rollfragments; not used

* import; worlds not world :)

* Option groups!

* ruff styling, fix

* ruff format styling!

* styling and capitalization of options

* small comment

* Cleaned up the "state_is_a_list" a little bit

* RUFF 🐶

* Changed filling the itempool for efficiency

Now, we start with 17 extra items in the item pool, it's quite likely you need at least 17 items (~80%?).
And then afterwards, we delete items if we overshoot the target of 1000, and add items if we haven't reached an achievable score of 1000 yet. Also, no need to recompute the entire logic when adding points.

* 🐶

* Removed plando "fix"

* Changed indent of score multiplier

* faster location function

* Comments to docstrings

* fixed making location closest to goal_score be goal_score

* options format

* iterate keys and values of a dict together

* small optimization ListState

* faster collection of categories

* return arguments instead of making a list (will 🐶 later)

* Instead of turning it into a tuple, you can just make a tuple literal

* remove .keys()

* change .random and used enumerate

* some readability improvements

* Remove location "0", we don't use that one

* Remove lookup_id_to_name entirely

I for sure don't use it, and as far as I know it's not one of the mandatory functions for AP, these are item_name_to_id and location_name_to_id.

* .append instead of += for single items, percentile function changed

Also an extra comment for location ids.

* remove ) too many

* Removed sorted from category list

* Hash categories (which makes it slower :( )

Maybe I messed up or misunderstood...
I'll revert this right away since it is 2x slower, probably because of sorted instead of sort?

* Revert "Hash categories (which makes it slower :( )"

This reverts commit 34f2c1aed8c8813b2d9c58896650b82a810d3578.

* temporary push: 40% faster generation test

Small changes in logic make the generation 40% faster.
I'll have to think about how big the changes are. I suspect they are rather limited.
If this is the way to go, I'll remove the temp file and redo the YachtWeights file, I'll remove the functions there and just put the new weights here.

* Add Points item category

* Reverse changes of bad idea :)

* ruff 🐶

* Use numpy and pmf function to speed up gen

Numpy has a built-in way to sum probability mass functions (pmf).
This shaves of 60% of the generation time :D

* Revert "Use numpy and pmf function to speed up gen"

This reverts commit 9290191cb323ae92321d6c2cfcfe8c27370f439b.

* Step inbetween to change the weights

* Changed the weights to make it faster

135 -> 81 seconds on 100 random yamls

* Adjusted max_dist, split dice_simulation function

* Removed nonlocal and pass arguments instead

* Change "weight-lists" to Dict[str, float]

* Removed the return from ini_locations.

Also added explanations to cat_weights

* Choice options; dont'use .value (will ruff later)

* Only put important options in slotdata

* 🐶

* Add Dict import

* Split the cache per player, limit size to 400.

* 🐶

* added , because of style

* Update apworld version to 2.0.6

2.0.5 is the apworld I released on github to be tested
I never separately released 2.0.4.

* Multiple smaller code improvements

- changed names in YachtWeights so we don't need to translate them in Rules anymore
- we now remember which categories are present in the game, and also put this in slotdata. This we do because only one of two categories is present in a game. If for some reason both are present (plando/getitem/startinventory), we now know which category to ignore
-

* 🐶 ruff

* Mostly minimize_extra_items improvements

- Change logic, generation is now even faster (0.6s per default yaml).
- Made the option 'minimize_extra_items' do a lot more, hopefully this makes the impact of Yacht Dice a little bit less, if you want that. Here's what is also does now:
 - you start with 2 dice and 2 rolls
 - there will be less locations/items at the start of you game

* ruff 🐶

* Removed printing options

* Reworded some option descriptions

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-21 19:59:21 +02:00
Silvris eaa8156061
MM2: fix Wily 5 Time Stopper rule (#3824)
* fix time stopper rule

* that was the entirely wrong rule actually
2024-08-21 16:20:16 +02:00
Trevor L 54a7bb5664
Blasphemous: Total overhaul (#3355)
* Blasphemous: WIP overhaul

* Entrance rule mistake

* stuff

* Getting closer

* Real?? Maybe??

* Don't fail me now 🙏

* Add starting location tests

* More tests (it still doesn't work actually 😔)

* REAL

* Add unreachable regions to test_reachability.py

* PR ready

- Remove unused functions from init
- Use group exclusive functions in rules
- Style changes

* Bump required client version

* Clean up unused imports

* Change slot data

* Review fixes

- Prevent strength calculations from including excess items
- Add new lines to ends of files
- Fix missed deprecated option and random usage in init

* Update option docstrings, add groups

* Add preprocessor files

* Update option docstrings again actually

* Update player strength calculation

* Rename group methods

* Fix missing logic for RESCUED_CHERUB_06

* Register indirect conditions

* Register indirect conditions (part 2)

* Update extracted logic, change slot data key

* Add region to excluded list

* A capital letter

* Use camelCase keys in preprocessor

* Write some of new setup guide

* Remove indents before list points

* Change locationinfo to list of dictonaries

* Finish docs, update extractor config and data

* Mark region_data.py as generated

* Suggested changes

* More suggested changes

* Suggested changes again

- Use OptionError
- Create list of disabled locations before looping
- Check if options are equal to str instead of int
- Clean up start location override
- Reword some of setup guide
- Organize location list
- Remove unnecessary escaped quotes from option docstrings
- Add world type to test base

* C# moment

* Requested changes

* Update .gitattributes

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-08-21 01:18:28 +02:00
Silvris 0e6e359747
Mega Man 2: Implement New Game (#3256)
* initial (broken) commit

* small work on init

* Update Items.py

* beginning work, some rom patches

* commit progress from bh branch

* deathlink, fix soft-reset kill, e-tank loss

* begin work on targeting new bhclient

* write font

* definitely didn't forget to add the other two hashes no

* update to modern options, begin colors

* fix 6th letter bug

* palette shuffle + logic rewrite

* fix a bunch of pointers

* fix color changes, deathlink, and add wily 5 req

* adjust weapon weakness generation

* Update Rules.py

* attempt wily 5 softlock fix

* add explicit test for rbm weaknesses

* fix difficulty and hard reset

* fix connect deathlink and off by one item color

* fix atomic fire again

* de-jank deathlink

* rewrite wily5 rule

* fix rare solo-gen fill issue, hopefully

* Update Client.py

* fix wily 5 requirements

* undo fill hook

* fix picopico-kun rules

* for real this time

* update minimum damage requirement

* begin move to procedure patch

* finish move to APPP, allow rando boobeam, color updates

* fix color bug, UT support?

* what do you mean I forgot the procedure

* fix UT?

* plando weakness and fixes

* sfx when item received, more time stopper edge cases

* Update test_weakness.py

* fix rules and color bug

* fix color bug, support reduced flashing

* major world overhaul

* Update Locations.py

* fix first found bugs

* mypy cleanup

* headerless roms

* Update Rom.py

* further cleanup

* work on energylink

* el fixes

* update to energylink 2.0 packet

* energylink balancing

* potentially break other clients, more balancing

* Update Items.py

* remove startup change from basepatch

we write that in patch, since we also need to clean the area before applying

* el balancing and feedback

* hopefully less test failures?

* implement world version check

* add weapon/health option

* Update Rom.py

* x/x2

* specials

* Update Color.py

* Update Options.py

* finally apply location groups

* bump minor version number instead

* fix duplicate stage sends

* validate wily 5, tests

* see if renaming fixes

* add shuffled weakness

* remove passwords

* refresh rbm select, fix wily 5 validation

* forgot we can't check 0

* oops I broke the basepatch (remove failing test later)

* fix solo gen fill error?

* fix webhost patch recognition

* fix imports, basepatch

* move to flexibility metric for boss validation

* special case boobeam trap

* block strobe on stage select init

* more energylink balancing

* bump world version

* wily HP inaccurate in validation

* fix validation edge case

* save last completed wily to data storage

* mypy and pep8 cleanup

* fix file browse validation

* fix test failure, add enemy weakness

* remove test seed

* update enemy damage

* inno setup

* Update en_Mega Man 2.md

* setup guide

* Update en_Mega Man 2.md

* finish plando weakness section

* starting rbm edge case

* remove * imports

* properly wrap later weakness additions in regen playthrough

* fix import

* forgot readme

* remove time stopper special casing

since we moved to proper wily 5 validation, this special casing is no longer important

* properly type added locations

* Update CODEOWNERS

* add animation reduction

* deprioritize Time Stopper in rush checks

* special case wily phase 1

* fix key error

* forgot the test

* music and general cleanup

* the great rename

* fix import

* thanks pycharm

* reorder palette shuffle

* account for alien on shuffled weakness

* apply suggestions

* fix seedbleed

* fix invalid buster passthrough

* fix weakness landing beneath required amount

* fix failsafe

* finish music

* fix Time Stopper on Flash/Alien

* asar pls

* Apply suggestions from code review

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* world helpers

* init cleanup

* apostrophes

* clearer wording

* mypy and cleanup

* options doc cleanup

* Update rom.py

* rules cleanup

* Update __init__.py

* Update __init__.py

* move to defaultdict

* cleanup world helpers

* Update __init__.py

* remove unnecessary line from fill hook

* forgot the other one

* apply code review

* remove collect

* Update rules.py

* forgot another

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-20 04:59:29 +02:00
NewSoupVi c4e7b6ca82
The Witness: Add "vague" hints making use of other games' region names and location groups (#2921)
* Vague hints work! But, the client will probably reveal some of the info through scouts atm

* Fall back on Everywhere if necessary

* Some of these failsafes are not necessary now

* Limit region size to 100 as well

* Actually... like this.

* Nutmeg

* Lol

* -1 for own player but don't scout

* Still make always/priority ITEM hints

* fix

* uwu notices your bug

* The hints should, like, actually work, you know?

* Make it a Toggle

* Update worlds/witness/hints.py

Co-authored-by: Bryce Wilson <gyroscope15@gmail.com>

* Update worlds/witness/hints.py

Co-authored-by: Bryce Wilson <gyroscope15@gmail.com>

* Make some suggested changes

* Make that ungodly equation a bit clearer in terms of formatting

* make that not sorted

* Add a warning about the feature in the option tooltip

* Make using region names experimental

* reword option tooltip

* Note about singleplayer

* Slight rewording again

* Reorder the order of priority a bit

* this condition is unnecessary now

* comment

* No wait the order has to be like this

* Okay now I think it's correct

* Another comment

* Align option tooltip with new behavior

* slight rewording again

* reword reword reword reword

* -

* ethics

* Update worlds/witness/options.py

Co-authored-by: Bryce Wilson <gyroscope15@gmail.com>

* Rename and slight behavior change for local hints

* I think I overengineered this system before. Make it more consistent and clear now

* oops I used checks by accident

* oops

* OMEGA OOPS

* Accidentally commited a print statemetn

* Vi don't commit nonsense challenge difficulty impossible

* This isn't always true but it's good enough

* Update options.py

* Update worlds/witness/options.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Scipio :3

* switch to is_event instead of checking against location.address

* oop

* Update test_roll_other_options.py

* Fix that unit test problem lol

* Oh is this not fixed in the apworld?

---------

Co-authored-by: Bryce Wilson <gyroscope15@gmail.com>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2024-08-20 01:34:40 +02:00
NewSoupVi f253dffc07
The Witness: Panel Hunt Mode (#3265)
* Add panel hunt options

* Make sure all panels are either solvable or disabled in panel hunt

* Pick huntable panels

* Discards in disable non randomized

* Set up panel hunt requirement

* Panel hunt functional

* Make it so an event can have multiple names

* Panel hunt with events

* Add hunt entities to slot data

* ruff

* add to hint data, no client sneding yet

* encode panel hunt amount in compact hint data

* Remove print statement

* my b

* consistent

* meh

* additions for lcient

* Nah

* Victory panels ineligible for panel hunt

* Panel Hunt Postgame option

* cleanup

* Add data generation file

* pull out set

* always disable gate ep in panel hunt

* Disallow certain challenge panels from being panel hunt panels

* Make panelhuntpostgame its own function, so it can be called even if normal postgame is enabled

* disallow PP resets from panel hunt

* Disable challenge timer and elevetor start respectively in disable hunt postgame

* Fix panelhunt postgame

* lol

* When you test that the bug is fixed but not that the non-bug is not unfixed

* Prevent Obelisks from being panel hunt panels

* Make picking panels for panel hunt a bit more sophisticated, if less random

* Better function maybe ig

* Ok maybe that was a bit too much

* Give advanced players some control over panel hunt

* lint

* correct the logic for amount to pick

* decided the jingle thing was dumb, I'll figure sth out client side. Same area discouragement is now a configurable factor, and the logic has been significantly rewritten

* comment

* Make the option visible

* Safety

* Change assert slightly

* We do a little logging

* number tweak & we do a lil logging

* we do a little more logging

* Ruff

* Panel Hunt Option Group

* Idk how that got here

* Update worlds/witness/options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/witness/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* remove merge error

* Update worlds/witness/player_logic.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* True

* Don't have underwater sliding bridge when you have above water sliding bridge

* These are not actually connected lol

* get rid of unnecessary variable

* Refactor compact hint function again

* lint

* Pull out Entity Hunt Picking into its own class, split it into many functions. Kept a lot of the comments tho

* forgot to actually add the new file

* some more refactoring & docstrings

* consistent naming

* flip elif change

* Comment about naming

* Make static eligible panels a constant I can refer back to

* slight formatting change

* pull out options-based eligibility into its own function

* better text and stuff

* lint

* this is not necessary

* capitalisation

* Fix same area discouragement 0

* Simplify data file generation

* Simplify data file generation

* prevent div 0

* Add Vault Boxes -> Vault Panels to replacements

* Update options.py

* Update worlds/witness/entity_hunt.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update entity_hunt.py

* Fix some events not working

* assert

* remove now unused function

* lint

* Lasers Activate, Lasers don't Solve

* lint

* oops

* mypy

* lint

* Add simple panel hunt unit test

* Add Panel Hunt Tests

* Add more Panel Hunt Tests

* Disallow Box Short for normal panel hunt

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-20 01:16:35 +02:00
KonoTyran c010c8c938
Minecraft: Update to new options system. (#3765)
* Move to new options system.
switch to using self.random
reformat rules file.

* further reformats

* fix tests to use new options system.

* fix slot data to not use self.multiworld

* I hate python

* new starting_items docstring to prepare for 1.20.5+ item components.
fix invalid json being output to starting_items

* more typing fixes.

* stupid quotes around type declarations

* removed unused variable in ItemPool.py
change null check in Structures.py

* update rules "self" variable to a "world: MinecraftWorld" variable

* get key, and not value for required bosses.
2024-08-20 00:58:30 +02:00
Doug Hoskisson 1e8a8e7482
Docs: `NetworkItem.player` (#3811)
* Docs: `NetworkItem.player`

In many contexts, it's difficult to tell whether this is the sending player or the receiving player.

* correct player info

* Update NetUtils.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

---------

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
2024-08-19 20:37:36 +02:00
NewSoupVi 182f7e24e5
The Witness: Fix Tunnels Theater Flower EP Access Logic + Add Unit Test for it (and Expert PP2) (#3807)
* Tunnels Theater Flowers fix + Flowers&PP2 Unit Tests

* copypaste

* Can just do it like this

* This is even better probably

* Also do some cleanup :3

* God damnit
2024-08-19 07:49:06 +02:00
Mysteryem 9277cb39ef
Core: Fix incorrect default state checked in MultiWorld.can_beat_game (#3813)
`MultiWorld.can_beat_game()` with no arguments would initially check if
`self.state` is beatable, but then would create an empty state,
`state = CollectionState(self)`, to sweep spheres from to determine if
the game is beatable. The issue was that `self.state` and the new empty
state could be different.

Currently, it seems that everywhere in Archipelago's codebase that calls
`MultiWorld.can_beat_game()` with no arguments or `starting_state=None`
has a `self.state` that only contains precollected items, so the new
empty state happens to result in an equivalent state, but this should
not be relied upon to always be the case.

This patch changes `can_beat_game()` to initially check if the new empty
state is beatable instead of `self.state`.

This appears to be a bug introduced way back in 27b6dd8bd7

Fixes #3742
2024-08-19 06:44:06 +02:00
gaithern 28a9709516
Kingdom Hearts: Implement New Game (#3201)
* Added Final Ansem Goal

* Update __init__.py

* Update Rules.py

* New EotW logic

* Update __init__.py

* Update __init__.py

* Update Items.py

* Update Rules.py

* Rename Location to be more meaningful, logic fixes

* Removed Aerith locations

* Change to allow randomized keyblade stats

* Fixed incorrect option description.  Fixed victory locations for alternative win condition settings

* Commit

* Lots of changes

* Fixes

* Fixes

* Update Rules.py

* Update Rules.py

* Update Rules.py

* Update Rules.py

* Fixes

* Update Rules.py

* Update Rules.py

* Update Options.py

* Old Book is not required

* Added Jungle Slider

* Add Cid Check

* Add Wonderland Book Check

* Add OC Green Trinity

* Add Inferno Band Event

* Add Kurt Zisa Zantetsuken and Unknown EXP Necklace checks

* Update Locations.py

* Fix Final Ansem Goal

* Update __init__.py

* Update __init__.py

* Add options to exclude super bosses and 100 acre wood

* Fix puppies trp, remove cid check

* Fix 100 Acre Wood Option

* Material to Empty Bottle

* Fixed rules, location names, etc

* Fix super bosses

* Add item + location groups, level sanity

* Fix location and item group names

* Add Bad Starting Weapons Option

* Logic Error for 100 Acre Wood

* Update Rules.py

* Update __init__.py

* Fixes related to randomized keyblade stats and super bosses

* Credits and Fixes

* Logic fixes, location name group changes

* Update Options.py

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update .gitignore

* Update CODEOWNERS

* Update docs/CODEOWNERS

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Fixed Atlantica item group name

* Update CODEOWNERS

* Update Client.py

* Update Items.py

* Update __init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Fixed report group name

* Fixes for PR

* Update Options.py

* Push changes for making the Final Rest Door appear, few option fixes

* Update Rules.py

* Website formatting, 0 min for reports, option description typo

* Create KH1Client.py

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update Options.py

* Update Options.py

* Update Rules.py

* Update Rules.py

* Update Rules.py

* Add Donald and Goofy Death Link

* Add fight logic for optional bosses

* Update __init__.py

* Update Options.py

* Update worlds/kh1/Options.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update Client.py

* Update kh1_en.md

* Update __init__.py

* Cleaning up for PR

* Update Client.py

* Added event locations for vanilla items

* Add proper location groups and auto hint synth shop items when entering

* so many changes

* Update Rules.py

* fixed oathkeeper and crabclaw logic

* Update Rules.py

* Update Rules.py

* Update Rules.py

* Update Rules.py

* Update en_Kingdom Hearts.md

* Update en_Kingdom Hearts.md

* fixing text

* Update kh1_en.md

* Addition of new key items

* Update Regions.py

* Push for start item from pool test

* Update worlds/kh1/Options.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Document update

* Update Rules.py

* Added starting world range and final rest goal option

* Update kh1_en.md

* Update en_Kingdom Hearts.md

* Update __init__.py

* Update __init__.py

* Clean up options descriptions

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Options.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/Client.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Fix grammar in document

* Update __init__.py

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Removed return type

* Update __init__.py

* Update __init__.py

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update __init__.py

* Fix missing i replacement, rework set rules to use "self" instead of a million arguments

* Update KH1Client.py

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

* Reformat rules, fix bug with exp mult, add to readme

* Clean up regions, fix client

* Fix item send prompt

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/en_Kingdom Hearts.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/test/test_goal.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Items.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Locations.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Regions.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Locations.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Locations.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Items.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Regions.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Regions.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/__init__.py

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

* Fix so many suggestions

* removed junk in missable locations option

* Update __init__.py

* Change credits order

* Update en_Kingdom Hearts.md

* Standardize punctuation

* Update en_Kingdom Hearts.md

* Update en_Kingdom Hearts.md

* Update Regions.py

* Removed "disclude" options in generation fillers

* Update Rules.py

* Update __init__.py

* Fix cemetery typo

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Add option groups and option presets

* Update worlds/kh1/__init__.py

That's a good idea!

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Presets.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* fixed HB rule and formatting on a line in Items.py

* Fix logic bug with Geppetto's House postcard

* Update Rules.py

* Update Options.py

* Update __init__.py

* Update __init__.py

* Huge under-the-hood update for PR

* More updates for PR

* Update worlds/kh1/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/kh1/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update __init__.py

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-19 00:39:37 +02:00
Scrungip 49a5b52774
VVVVVV: Make unnecessary Trinkets filler (#3806)
* Make unnecessary trinkets filler

* Proper syntax

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-18 23:03:57 +02:00
Doug Hoskisson 2b1802ccee
Core: type for `CommonContext.ui` (#3796)
* Core: type for `CommonContext.ui`

* use `Optional`
2024-08-17 03:19:16 +02:00
Bryce Wilson f5218faea7
Pokemon Emerald: Ensure dig tutor is always usable (#3660)
* Pokemon Emerald: Ensure dig tutor is always usable

* Pokemon Emerald: Clarify comment

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-16 22:23:47 +02:00
Exempt-Medic 81092247c6
Core: early_local != local_early #3780 2024-08-16 22:20:20 +02:00
Kaito Sinclaire ca96e7e294
Fix !remaining for cross-world items (#3732)
* Fix !remaining for other worlds

* Typing fixes for the previous change

* Update LocationStore test to match what get_remaining now returns
2024-08-16 22:20:02 +02:00
digiholic c014c5a54a
[OSRS] Fixes Incorrect filler item names causing failures on tests. (#3768)
* Updates filler item names to match the actual item names

* Adds more descriptive error message in case this error comes back

* Properly raises exception instead of just text

* Replaces exception with assert
2024-08-16 22:10:30 +02:00
Emily e9c863dffd
Docs: Update 'tag' documentation (#3632)
* Add tag docs for HintGame

* Apply suggestions from code review

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

* Make Tracker/TextOnly consistent with previous commit

* Apply suggestion

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

* fix spacing

* Apply suggestion

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

* apply suggestion correcting footnotes

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-16 21:04:23 +02:00
Mysteryem 7eda4c47f8
TLOZ: Fix non-deterministic item pool generation (#3779)
* TLOZ: Fix non-deterministic item pool generation

The way the item pool was constructed involved iterating unions of sets.
Sets are unordered, so the order of iteration of these combined sets
would be non-deterministic, resulting in the items in the item pool
being generated in a different order with the same seed.

Rather than creating unions of sets at all, the original code has been
replaced with using Counter objects. As a dict subclass, Counter
maintains insertion order, and its update() method makes it simple to
combine the separate item dictionaries into a single dictionary with the
total count of each item across each of the separate item dictionaries.

Fixes #3664 - After investigating more deeply, the only differences I
could find between generations of the same seed was the order of items
created by TLOZ, so this patch appears to fix the non-deterministic
generation issue. I did manage to reproduce the non-deterministic
behaviour with just TLOZ in the end, but it was very rare. I'm not
entirely sure why generating with SMZ3 specifically would cause the
non-deterministic behaviour in TLOZ to be frequently present, whereas
generating with other games or multiple TLOZ yamls would not.

* Change import order

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-08-16 20:57:04 +02:00
Scipio Wright 474a3181c6
TUNIC: Give the fox a gun (in logic) (very small PR) (#3790)
* Add bomb wall logic

* Remove option call from can_shop

* Gun for the envoy blocking Quarry

* has_sword -> can_shop on cube cave entrance region
2024-08-16 20:53:54 +02:00
Star Rauchenberger 4af6927e23
Lingo: Fixed Initiated-side Eight Door not opening (#3793) 2024-08-16 20:52:16 +02:00
Exempt-Medic 06df072095
Core: Require excluded locations to be reachable with full/locations accessibility (#3802)
* Make excludeds reachable

* Update all_state tests
2024-08-16 20:49:37 +02:00
agilbert1412 56aabe51b8
Stardew Valley: Add Quality Bobber in the logic rules for fish quality gold and above #3792 2024-08-14 17:07:06 +02:00
Scipio Wright 5e5f24cdd2
TUNIC: Add off and on aliases for the Entrance Rando option #3794 2024-08-14 16:55:02 +02:00
Exempt-Medic 9fbaa6050f
I have no idea (#3791) 2024-08-14 00:21:42 -04:00
Scipio Wright 0af31c71e0
TUNIC: Swap from multiworld.get to world.get for applicable things (#3789)
* Swap from multiworld.get to world.get for applicable things

* Why was this even here in the first place?
2024-08-14 02:35:08 +02:00
Aaron Wagener 169da1b1e0
Tests: fix the all games multiworld test (#3788) 2024-08-14 00:31:26 +02:00
Aaron Wagener 8e7ea06f39
Core: dump all item placements for generation failures. (#3237)
* Core: dump all item placements for generation failures

* pass the multiworld from remaining fill

* change how the args get handled to fix formatting

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-08-14 00:17:42 +02:00
Aaron Wagener 96d48a923a
Core: recontextualize `CollectionState.collect` (#3723)
* Core: renamed `CollectionState.collect` arg from `event` to `prevent_sweep` and remove forced collection

* Update TestDungeon.py

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-08-13 22:28:05 +02:00
Exempt-Medic dcaa2f7b97
Core: Two Small Fixes (#3782) 2024-08-13 18:02:09 +02:00
NewSoupVi 50330cf32f
Core: Remove broken unused code from Options.py (#3781)
"Unused" is a baseless assertion, but this code path has been crashing on the first statement for 6 months and noone's complained
2024-08-12 19:32:14 +02:00
Exempt-Medic 67520adcea
Core: Error on empty options.as_dict (#3773)
* Error on empty options.as_dict

* ValueError instead

* Apply suggestions from code review

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

---------

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-08-12 02:13:45 +02:00
Exempt-Medic a3e54a951f
Undertale: Fix slot_data and options.as_dict() (#3774)
* Undertale: Fixing slot_data

* Booleans were difficult
2024-08-12 01:53:40 +02:00
qwint ae0abd3821
Core: change start inventory from pool to warn when nothing to remove (#3158)
* makes start inventory from pool warn and fixes the itempool to match when it can not find a matching item to remove

* calc the difference correctly

* save new filler and non-removed items differently so we don't remove existing items at random
2024-08-12 00:57:59 +02:00
Scipio Wright 21bbf5fb95
TUNIC: Add note to Universal Tracker stuff #3772 2024-08-12 00:24:30 +02:00
Jarno 09e052c750
Timespinner: Fix eels check logic #3777 2024-08-12 00:24:09 +02:00
Scipio Wright 68a92b0c6f
Clique: Update to new options API (#3759) 2024-08-11 14:47:17 +02:00
Silvris 8e06ab4f68
Core: fix invalid __package__ of zipped worlds (#3686)
* fix invalid package fix

* add comment describing fix
2024-08-10 13:49:32 +02:00
black-sliver 9dba39b606
SoE: fix determinism (#3745)
Fixes randomly placed ingredients not being deterministic (depending on settings)
and in turn also fixes logic not being deterministic if they get replaced by fragments.
2024-08-10 13:08:24 +02:00
Exempt-Medic a6f376b02e
TLOZ: world: multiworld (#3752) 2024-08-09 22:38:42 +02:00
Kaito Sinclaire c66a8605da
DOOM, DOOM II: Update steam URLs (#3746) 2024-08-09 17:04:59 +02:00
Mysteryem ac7590e621
HK: fix iterating all worlds instead of only HK worlds in stage_pre_fill (#3750)
Would cause generation to fail when generating with HK and another game.

Mistake in 6803c373e5.
2024-08-09 17:02:41 +02:00
Mysteryem 30f97dd7de
Core: Speed up CollectionState.copy() using built-in copy methods (#3678)
All the types being copied are built-in types with their own `copy()`
methods, so using the `copy` module was a bit overkill and also slower.

This patch replaces the use of the `copy` module in
`CollectionState.copy()` with using the built-in `.copy()` methods.

The copying of `reachable_regions` and `blocked_connections` was also
iterating the keys of each dictionary and then looking up the value in
the dictionary for that key. It is faster, and I think more readable, to
iterate the dictionary's `.items()` instead.

For me, when generating a multiworld including the template yaml of
every world with `python -O .\Generate.py --skip_output`, this patch
saves about 2.1s. The overall generation duration for these yamls varies
quite a lot, but averages around 160s for me, so on average this patch
reduced overall generation duration (excluding output duration) by
around 1.3%.

Timing comparisons were made by calling time.perf_counter() at the start
and end of `CollectionState.copy()`'s body, and summing the differences
between the starts and ends of the method body into a global variable
that was printed at the end of generation.

Additional timing comparisons were made, using the `timeit` module, of
the individual function calls or dictionary comprehensions used to
perform the copying.

The main performance cost was `copy.deepcopy()`, which gets slow as the
number of keys multiplied by the number of values within the
sets/Counters gets large, e.g., to deepcopy a `dict[int, Counter[str]]`
with 100 keys and where each Counter contains 100 keys was 30x slower
than most other tested copying methods. Increasing the number of dict
keys or Counter keys only makes it slower.
2024-08-09 14:25:39 +02:00
Mysteryem 6e41c60672
Core: Check parent_region.can_reach first in Location.can_reach (#3724)
* Core: Check parent_region.can_reach first in Location.can_reach

The comment about self.access_rule computing faster on average appears
to no longer be correct with the current caching system for region
accessibility, resulting in self.parent_region.can_reach computing
faster on average.

Generation of template yamls for each game that does not require a rom
to generate, generated with `python -O .\Generate.py --seed 1`
(all durations averaged over at 4 or 5 generations):

Full generation with `spoiler: 1` and no progression balancing:
89.9s -> 72.6s
Only output from above case:
2.6s -> 2.2s

Full generation with `spoiler: 3` and no progression balancing:
769.9s -> 627.1s
Only playthrough calculation + paths from above case:
680.5s -> 555.3s

Full generation with `spoiler: 1` with default progression balancing:
123.5s -> 98.3s
Only progression balancing from above case:
11.3s -> 9.6s

* Update BaseClasses.py

* Update BaseClasses.py

* Update BaseClasses.py

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-08-09 14:13:01 +02:00
Natalie Weizenbaum 5efb3fd2b0
DS3: Version 3.0.0 (#3128)
* Update worlds/dark_souls_3/Locations.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Fix Covetous Silver Serpent Ring location

* Update location groups

This should cover pretty much all of the seriously hidden items. It
also splits out miniboss drops, mimic drops, and hostile NPC drops.

* Remove the "Guarded by Keys" group

On reflection, I don't think this is actually that useful. It'll also
get a lot muddier once we can randomize shops and ashes become
pseudo-"keys".

* Restore Knight Slayer's Ring classification

* Support infusions/upgrades in the new DS3 mod system

* Support random starting loadouts

* Make an item's NPC status orthogonal to its category

* Track location groups with flags

* Track Archipelago/Offline mismatches on the server

Also fix a few incorrect item names.

* Add additional locations that are now randomizable

* Don't put soul and multiple items in shops

* Add an option to enable whether NG+ items/locations are included

* Clean up useful item categorization

There are so many weapons in the game now, it doesn't make sense to
treat them all as useful

* Add more variety to filler items

* Iron out a few bugs and incompatibilities

* Fix more silly bugs

* Get tests passing

* Update options to cover new item types

Also recategorize some items.

* Verify the default values of `Option`s.

Since `Option.verify()` can handle normalization of option names, this allows options  to define defaults which rely on that normalization. For example, it allows a world to exclude certain locations by default.

This also makes it easier to catch errors if a world author accidentally sets an invalid default.

* Make a few more improvements and fixes

* Randomize Path of the Dragon

* Mark items that unlock checks as useful

These items all unlock missable checks, but they're still good to ahve in the game for variety's sake.

* Guarantee more NPC quests are completable

* Fix a syntax error

* Fix rule definition

* Support enemy randomization

* Support online Yhorm randomization

* Remove a completed TODO

* Fix tests

* Fix force_unique

* Add an option to smooth out upgrade item progression

* Add helpers for setting location/entrance rules

* Support smoother soul item progression

* Fill extra smoothing items into conditional locations as well as other worlds

* Add health item smoothing

* Handle infusions at item generation time

* Handle item upgrades at genreation time

* Fix Grave Warden's Ashes

* Don't overwrite old rules

* Randomize items based on spheres instead of DS3 locations

* Add a smoothing option for weapon upgrades

* Add rules for crow trades

* Small fixes

* Fix a few more bugs

* Fix more bugs

* Try to prevent Path of the Dragon from going somewhere it doesn't work

* Add the ability to provide enemy presets

* Various fixes and features

* Bug fixes

* Better Coiled Sword placement

* Structure DarkSouls3Location more like DarkSouls3Item

* Add events to make DS3's spheres more even

* Restructure locations to work like items do now

* Add rules for more missable locations

* Don't add two Storm Rulers

* Place Hawk Ring in Farron Keep

* Mark the Grass Crest Shield as useful

* Mark new progression items

* Fix a bug

* Support newer better Path of the Dragon code

* Don't lock the player out of Coiled Sword

* Don't create events for missable locations

* Don't throw strings

* Don't smooth event items

* Properly categorize Butcher Knife

* Be more careful about placing Yhorm in low-randomization scenarios

* Don't try to smooth DLC items with DLC disabled

* Fix another Yhorm bug

* Fix upgrade/infusion logic

* Remove the PoolType option

This distinction is no longer meaningful now that every location in
the game of each type is randomized

* Categorize HWL: Red Eye Orb as an NPC location

* Don't place Storm Ruler on CA: Coiled Sword

* Define flatten() locally to make this APWorld capable

* Fix some more Leonhard weirdness

* Fix unique item randomization

* Don't double Twin Dragon Greatshield

* Remove debugging print

* Don't add double Storm Ruler

Also remove now-redundant item sorting by category in create_items.

* Don't add double Storm Ruler

Also remove now-redundant item sorting by category in create_items.

* Add a missing dlc_enabled check

* Use nicer options syntax

* Bump data_version

* Mention where Yhorm is in which world

* Better handle excluded events

* Add a newline to Yhorm location

* Better way of handling excluded unradomized progression locations

* Fix a squidge of nondeterminism

* Only smooth items from this world

* Don't smooth progression weapons

* Remove a location that doesn't actually exist in-game

* Classify Power Within as useful

* Clarify location names

* Fix location requirements

* Clean up randomization options

* Properly name Coiled Sword location

* Add an option for configuring how missable items are handled

* Fix some bugs from location name updates

* Fix location guide link

* Fix a couple locations that were busted offline

* Update detailed location descriptions

* Fix some bugs when generating for a multiworld

* Inject Large Leather Shield

* Fix a few location issues

* Don't allow progression_skip_balancing for unnecessary locs

* Update some location info

* Don't uniquify the wrong items

* Fix some more location issues

* More location fixes

* Use hyphens instead of parens for location descriptions

* Update and fix more locations

* Fix Soul of Cinder boss name

* Fix some logic issues

* Add item groups and document item/location groups

* Fix the display name for "Impatient Mimics"

* Properly handle Transposing Kiln and Pyromancer's Flame

* Testing

* Some fixes to NPC quests, late basin, and transposing kiln

* Improve a couple location names

* Split out and improve missable NPC item logic

* Don't allow crow trades to have foreign items

* Fix a variable capture bug

* Make sure early items are accessible early even with early Castle

* Mark ID giant slave drops as missable

* Make sure late basin means that early items aren't behind it

* Make is_location_available explicitly private

* Add an _add_item_rule utility that checks availability

* Clear excluded items if excluded_locations == "unnecessary"

* Don't allow upgrades/infusions in crow trades

* Fix the documentation for deprecated options

* Create events for all excluded locations

This allows `can_reach` logic to work even if the locations are
randomized.

* Fix up Patches' and Siegward's logic based on some manual testing

* Factor out more sub-methods for setting location rules

* Oops, left these in

* Fixing name

* Left that in too

* Changing to NamedRange to support special_range_names

* Alphabetizing

* Don't call _is_location_available on foreign locations

* Add missing Leonhard items

* Changing late basin to have a post-small-doll option

* Update basin option, add logic for some of Leonhard Hawkwood and Orbeck

* Simplifying an option, fixing a copy-paste error

* Removing trailing whitespace

* Changing lost items to go into start inventory

* Revert Basin changes

* Oops

* Update Options.py

* Reverting small doll changes

* Farron Keep boss requirement logic

* Add Scroll for late_dlc

* Fixing excluded unnecessary locations

* Adding Priestess Ring as being after UG boss

* Removing missable from Corvian Titanite Slab

* Adding KFF Yhorm boss locks

* Screams about Creighton

* Elite Knight Set isn't permanently missable

* Adding Kiln requirement to KFF

* fixing valid_keys and item groups

* Fixing an option-checker

* Throwing unplaceable Storm Ruler into start inventory

* Update locations

* Refactor item injection

* Update setup doc

* Small fixes

* Fix another location name

* Fix injection calculation

* Inject guaranteed items along with progression items

* Mark boss souls as required for access to regions

This allows us to set quest requirements for boss souls and have them
automatically propagated to regions, means we need less machinery for
Yhorm bosses, and allows us to get rid of a few region-transition
events.

* Make sure Sirris's quest can be completed before Pontiff

* Removing unused list

* Changing dict to list

* Removing unused test

* Update __init__.py

* self.multiworld.random -> self.random (#9)

* Fix some miscellaneous location issues

* Rewrite the DS3 intro page/FAQ

* Removing modifying the itempool after fill (#7)

Co-authored-by: Natalie Weizenbaum <nweiz@google.com>

* Small fixes to the setup guide (#10)

Small fixes, adding an example for connecting

* Expanded Late Basin of Vows and Late DLC (#6)

* Add proper requirements for CD: Black Eye Orb

* Fix Aldrich's name

* Document the differences with the 2.x.x branch

* Don't crash if there are more items than locations in smoothing

* Apply suggestions from code review

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Code review

* Fix _replace_with_filler

* Don't use the shared flatten function in SM

* Track local items separately rather than iterating the multiworld

* Various formatting/docs changes suggested by PyCharm (#12)

* Drop deprecated options

* Rename "offline randomizer" to "static randomizer" which is clearer

* Move `enable_*_locations` under removed options.

* Avoid excluded locations for locally-filled items

* Adding Removed options to error (#14)

* Changes for WebHost options display and the options overhaul

* unpack iterators in item list (#13)

* Allow worlds to add options to prebuilt groups

Previously, this crashed because `typing.NamedTuple` fields such as
`group.name` aren't assignable. Now it will only fail for group names
that are actually incorrectly cased, and will fail with a better error
message.

* Style changes, rename exclude behavior options, remove guaranteed items option

* Spacing/Formatting (#18)

* Various Fixes (#19)

* Universally Track Yhorm (#20)

* Account for excluded and missable

* These are behaviors now

* This is singular, apparently

* Oops

* Fleshing out the priority process

* Missable Titanite Lizards and excluded locations (#22)

* Small style/efficiency changes

* Final passthrough fixes (#24)

* Use rich option formatting

* Make the behavior option values actual behaviors (#25)

* Use !=

* Remove unused flatten utility

* Some changes from review (#28)

* Fixing determinism and making smooth faster (#29)

* Style change

* PyCharm and Mypy fixes (#26)

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Change yhorm default (#30)

* Add indirect condition (#27)

* Update worlds/dark_souls_3/docs/locations_en.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Ship all item IDs to the client

This avoids issues where items might get skipped if, for instance,
they're only in the starting inventory.

* Make sure to send AP IDs for infused/upgraded weapons

* Make `RandomEnemyPresetOption` compatible with ArchipelagoMW/Archipelago#3280 (#31)

* Fix cast

* More typing and small fixes (#32)

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: Exempt-Medic <ExemptMedic@Gmail.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-08-09 12:14:26 +02:00
qwint 6803c373e5
HK: add grub hunt goal (#3203)
* makes grub hunt goal option that calculates the total available grubs (including item link replacements) and requires all of them to be gathered for goal completion

* update slot data name for grub count

* add option to set number needed for grub hub

* updates to grub hunt goal based on review

* copy/paste fix

* account for 'any' goal and fix overriding non-grub goals

* making sure godhome is in logic for any and removing redundancy on completion condition

* fix typing

* i hate typing

* move to stage_pre_fill

* modify "any" goal so all goals are in logic under minimal settings

* rewrite grub counting to create lookups for grubs and groups that can be reused

* use generator instead of list comprehension

* fix whitespace merging wrong

* minor code cleanup
2024-08-08 20:33:13 +02:00
Louis M 575c338aa3
Aquaria: Logic bug fixes (#3679)
* Fixing logic bugs

* Require energy attack in the cathedral and energy form in the body

* King Jelly can be beaten easily with only the Dual Form

* I think that I have a problem with my left and right...

* There is a monster that is blocking the path, soo need attack to pass

* The Li cage is not accessible without the Sunken city boss

* Removing useless space.

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Two more minors logic modification

* Adapting tests to af9b6cd

* Reformat the Region file

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-08 00:19:52 +02:00
Mysteryem 05ce29f7dc
RoR2: Remove recursion from explore mode access rules (#3681)
The access rules for "<Environment name> Chest n", "<Environment name>
Shrine n" etc. locations recursively called state.can_reach() for the
n-1 location name, with the n=1 location being the only location to have
the actual access rule set.

This patch removes the recursion, instead setting the actual access rule
directly on each location, increasing the performance of checking
accessibility of n>1 locations.

Risk of Rain 2 was already quite fast to generate despite the recursion
in the access rules, but with this patch, generating a multiworld with
200 copies of the template RoR2 yaml (and progression balancing
disabled through a meta.yaml) goes from about 18s to about 6s for me.

From generating the same seed before and after this patch, the same
result is produced.
2024-08-07 23:57:07 +02:00
JaredWeakStrike 74697b679e
KH2: Update the docs to support steam in the setup guide (#3711)
* doc updates

* add steam link

* Update worlds/kh2/docs/setup_en.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update setup_en.md

* Forgot to include these

* Consistent styling

* :)

* version 3.3.0

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-07 23:56:22 +02:00
Scipio Wright cf6661439e
TUNIC: Sort entrances in the spoiler log (#3733)
* Sort entrances in spoiler log

* Rearrange portal list to closer match the vanilla game order, for better spoiler and because I already did this mod-side

* Add break (thanks vi)
2024-08-07 18:18:50 +02:00
Scipio Wright 6297a4efa5
TUNIC: Fix missing traversal req #3740 2024-08-07 18:01:41 +02:00
digiholic 8ddb49f071
OSRS: Implement New Game (#1976)
* MMBN3: Press program now has proper color index when received remotely

* Initial commit of OSRS untangled from MMBN3 branch

* Fixes some broken region connections

* Removes some locations

* Rearranges locations to fill in slots left by removed locations

* Adds starting area rando

* Moves Oak and Willow trees to resource regions

* Fixes various PEP8 violations

* Refactor of regions

* Fixes variable capture issue with region rules

* Partial completion of brutal grind logic

* Finishes can_reach_skill function

* Adds skill requirements to location rules, fixes regions rules

* Adds documentation for OSRS

* Removes match statement

* Updates Data Version to test mode to prevent item name caching

* Fixes starting spawn logic for east varrock

* Fixes river lum crossing logic to not assume you can phase across water

* Prevents equipping items when you haven't unlocked them

* Changes canoe logic to not require huge levels

* Skeletoning out some data I'll need for variable task system

* Adds csvs and parser for logic

* Adds Items parsing

* Fixes the spawning logic to not default to Chunksanity when you didn't pick it

* Begins adding generation rules for data-driven logic

* Moves region handling and location creating to different methods

* Adds logic limits to Options

* Begun the location generation has

* Randomly generates tasks for each skill until populated

* Mopping up improper names, adding custom logic, and fixes location rolling

* Drastically cleans up the location rolling loop

* Modifies generation to properly use local variables and pass unit tests

* Game is now generating, but rules don't seem to work

* Lambda capture, my old nemesis. We meet again

* Fixes issue with Corsair Cove item requirement causing logic loop

* Okay one more fix, another variable capture

* On second thought lets not have skull sceptre tasks. 'Tis a silly place

* Removes QP from item pool (they're events not items)

* Removes Stronghold floor tasks, no varbit to track them

* Loads CSV with pkutil so it can be used in apworld

* Fixes logic of skill tasks and adds QP requirements to long grinds

* Fixes pathing in pkgutil call

* Better handling for empty task categories, no longer throws errors

* Fixes order for progressive tasks, removes un-checkable spider task

* Fixes logic issues related to stew and the Blurite caves

* Fixes issues generating causing tests to sporadically fail

* Adds missing task that caused off-by-one error

* Updates to new Options API

* Updates generation to function properly with the Universal Tracker (Thanks Faris)

* Replaces runtime CSV parsing with pre-made python files generated from CSVs

* Switches to self.random and uses random.choice instead of doing it manually

* Fixes to typing, variable names, iterators, and continue conditions

* Replaces Name classes with Enums

* Fixes parse error on region special rules

* Skill requirements check now returns an accessrule instead of being one that checks options

* Updates documentation and setup guide

* Adjusts maximum numbers for combat and general tasks

* Fixes region names so dictionary lookup works for chunksanity

* Update worlds/osrs/docs/en_Old School Runescape.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update worlds/osrs/docs/en_Old School Runescape.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Updates readme.md and codeowners doc

* Removes erroneous East Varrock -> Al Kharid connection

* Changes to canoe logic to account for woodcutting level options

* Fixes embarassing typo on 'Edgeville'

* Moves Logic CSVs to separate repository, addresses suggested changes on PR

* Fixes logic error in east/west lumbridge regions. Fixes incorrect List typing in main

* Removes task types with weight 0 from the list of rollable tasks

* Missed another place that the task type had to be removed if 0 weight

* Prevents adding an empty task weight if levels are too restrictive for tasks to be added

* Removes giant blank space in error message

* Adds player name to error for not having enough available tasks

---------

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
2024-08-06 23:13:11 +02:00
Exempt-Medic 90446ad175
ChecksFinder: Refactor/Cleaning (#3725)
* Update ChecksFinder

* minor cleanup

* Check for compatible name

* Enable APWorld

* Update setup_en.md

* Update en_ChecksFinder.md

* The client is getting updated instead

* Qwint suggestions, ' -> ", streamline fill_slot_data

* Oops, too many refactors

---------

Co-authored-by: SunCat <suncat.game@ya.ru>
2024-08-06 16:39:56 +02:00
Exempt-Medic 98bb8517e1
Docs: Missed Full Accessibility mention/conversion #3734 2024-08-06 00:00:33 +02:00
Exempt-Medic 203c8f4d89
Pokemon R/B: Removing Floats from NamedRange #3717 2024-08-05 23:40:16 +02:00
Aaron Wagener c0ef02d6fa
Core: fix missing import for `MultiWorld.link_items()` (#3731) 2024-08-04 12:55:34 +01:00
Exempt-Medic 4620493828
Spire: Convert options, clean up random calls, and add DeathLink (#3704)
* Convert StS options

* probably a bad idea

* Update worlds/spire/Options.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

---------

Co-authored-by: Kono Tyran <Kono@koifysh.dev>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2024-07-31 18:27:35 +02:00
wildham 75b8c7891c
Docs: Add FFMQ French Setup Guide + Minor fixes to English Guide (#3590)
* Add docs

* Fix character

* Configuration

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* ajuster

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* inclure

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* doublon

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* remplissage

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* autre

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* pouvoir

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* mappemonde

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* apostrophes

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* virgule

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* fournir

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* apostrophes 2

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* snes9x

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* apostrophes 3

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* options

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* lien

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* de laquelle

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* Étape de génération

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* apostrophes 4

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* également

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* guillemets

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* guillemets 2

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* adresse

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* Connect

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* seed

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>

* Changer fichier yaml pour de configuration

* Fix capitalization

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Fix capitalization 2

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Fix typo+Add link to fr/en info page

---------

Co-authored-by: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
2024-07-31 17:40:45 +02:00
Aaron Wagener 53bc4ffa52
Options: Always verify keys for VerifyKeys options (#3280)
* Options: Always verify keys for VerifyKeys options

* fix PlandoTexts

* use OptionError and give a slightly better error message for which option it is

* add the player name to the error

* don't create an unnecessary list

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-07-31 17:37:52 +02:00
Trevor L 91f7cf16de
Bomb Rush Cyberfunk: Fix Coil quest being in glitched logic too early (#3720)
* Update Rules.py

* Update Rules.py
2024-07-31 17:32:51 +02:00
GodlFire 7c8ea34a02
Shivers: New features and removes two missed options using the old options API (#3287)
* Adds an option to have pot pieces placed local/non-local/anywhere

Shivers nearly always finishes last in multiworld games due to the fact you need all 20 pot pieces to win and the pot pieces open very few location checks. This option allows the pieces to be placed locally. This should allow Shivers to be finished earlier.

* New option: Choose how many ixupi captures are needed for goal completion

New option: Choose how many ixupi captures are needed for goal completion

* Fixes rule logic for location 'puzzle solved three floor elevator'

Fixes rule logic for location 'puzzle solved three floor elevator'. Missing a parenthesis caused only the key requirement to be checked for the blue maze region.

* Merge branch 'main' of https://github.com/GodlFire/Shivers

* Revert "Merge branch 'main' of https://github.com/GodlFire/Shivers"

This reverts commit bb08c3f0c2ef148fd24d7c7820cdfe936f7196e2.

* Fixes issue with office elevator rule logic.

* Bug fix, missing logic requirement for location 'Final Riddle: Guillotine Dropped'

Bug fix, missing logic requirement for location 'Final Riddle: Guillotine Dropped'

* Moves plaque location to front for better tracker referencing.

* Tiki should be Shaman.

* Hanging should be Gallows.

* Merrick spelling.

* Clarity change.

* Changes new option to use new option API

Changes new option to use new option API

* Added sub regions for Ixupi

-Added sub regions for Ixupi and moved ixupi capture checks into the sub region.
-Added missing wax capture possible spot in Shaman room

* Adds option for ixupi captures to be priority locations

Adds option for ixupi captures to be priority locations

* Consistency

Consistency

* Changes ixupi captures priority to default on toggle

Changes ixupi captures priority to default on toggle

* Docs update

-Updated link to randomizer
-Update some text to reflect the latest functionality
-Replaced 'setting' with 'option'

* New features/bug fixes

-Adds an option to have completed pots in the item pool
-Moved subterranean world information plaque to maze staircase

* Cleanup

Cleanup

* Fixed name for moved location

When moving a location and renaming it I forgot to fix the name in a second spot.

* Squashed commit of the following:

commit 630a3bdfb9414d8c57154f29253fce0cf67b6436
Merge: 8477d3c8 5e579200
Author: GodlFire <46984098+GodlFire@users.noreply.github.com>
Date:   Mon Apr 1 19:08:48 2024 -0600

    Merge pull request #10 from ArchipelagoMW/main

    Merge main into branch

commit 5e5792009c
Author: Alchav <59858495+Alchav@users.noreply.github.com>
Date:   Mon Apr 1 12:08:21 2024 -0500

    LttP: delete playerSettings.yaml (#3062)

commit 9aeeeb077a
Author: CaitSith2 <d_good@caitsith2.com>
Date:   Mon Apr 1 06:07:56 2024 -0700

    ALttP: Re-mark light/dark world regions after applying plando connections (#2964)

commit 35458380e6
Author: Bryce Wilson <gyroscope15@gmail.com>
Date:   Mon Apr 1 07:07:11 2024 -0600

    Pokemon Emerald: Fix wonder trade race condition (#2983)

commit 4ac1866689
Author: Alchav <59858495+Alchav@users.noreply.github.com>
Date:   Mon Apr 1 08:06:31 2024 -0500

    ALTTP: Skull Woods Inverted fix (#2980)

commit 4aa03da66e
Author: Fabian Dill <Berserker66@users.noreply.github.com>
Date:   Mon Apr 1 15:06:02 2024 +0200

    Factorio: fix attempting to create savegame with not filename safe characters (#2842)

commit 24a03bc8b6
Author: Silvris <58583688+Silvris@users.noreply.github.com>
Date:   Mon Apr 1 08:02:26 2024 -0500

    KDL3: fix shuffled animals not actually being random (#3060)

commit f813a7005f
Author: Aaron Wagener <mmmcheese158@gmail.com>
Date:   Sun Mar 31 11:11:10 2024 -0500

    The Messenger: update docs formatting and fix outdated info (#3033)

    * The Messenger: update docs formatting and fix outdated info

    * address review feedback

    * 120 chars

commit 2a0b7e0def
Author: LiquidCat64 <74896918+LiquidCat64@users.noreply.github.com>
Date:   Sun Mar 31 09:55:55 2024 -0600

    CV64: A couple of very small docs corrections. (#3057)

commit 03d47e460e
Author: Ixrec <ericrhitchcock@gmail.com>
Date:   Sun Mar 31 16:55:08 2024 +0100

    A Short Hike: Clarify installation instructions (#3058)

    * Clarify installation instructions

    * don't mention 'config' folder since it isn't created until the game starts

commit e546c0f7ff
Author: Silvris <58583688+Silvris@users.noreply.github.com>
Date:   Sun Mar 31 10:50:31 2024 -0500

    Yoshi's Island: add patch suffix (#3061)

commit 2ec93ba82a
Author: Bryce Wilson <gyroscope15@gmail.com>
Date:   Sun Mar 31 09:48:59 2024 -0600

    Pokemon Emerald: Fix inconsistent location name (#3065)

commit 4e3d396394
Author: Aaron Wagener <mmmcheese158@gmail.com>
Date:   Sun Mar 31 10:47:11 2024 -0500

    The Messenger: Fix precollected notes not being removed from the itempool (#3066)

    * The Messenger: fix precollected notes not being properly removed from pool

    * The Messenger: bump required client version

commit 72c53513f8
Author: Fabian Dill <Berserker66@users.noreply.github.com>
Date:   Sun Mar 31 03:57:59 2024 +0200

    WebHost: fix /check creating broken yaml files if files don't end with a newline (#3063)

commit b7ac6a4cbd
Author: Aaron Wagener <mmmcheese158@gmail.com>
Date:   Fri Mar 29 20:14:53 2024 -0500

    The Messenger: Fix various portal shuffle issues (#2976)

    * put constants in a bit more sensical order

    * fix accidental incorrect scoping

    * fix plando rules not being respected

    * add docstrings for the plando functions

    * fix the portal output pools being overwritten

    * use shuffle and pop instead of removing by content so plando can go to the same area twice

    * move portal pool rebuilding outside mapping creation

    * remove plando_connection cleansing since it isn't shared with transition shuffle

commit 5f0112e783
Author: Zach Parks <zach@alliware.com>
Date:   Fri Mar 29 19:13:51 2024 -0500

    Tracker: Add starting inventory to trackers and received items table. (#3051)

commit bb481256de
Author: Aaron Wagener <mmmcheese158@gmail.com>
Date:   Thu Mar 28 21:48:40 2024 -0500

    Core: Make fill failure error more human parseable (#3023)

commit 301d9de975
Author: Aaron Wagener <mmmcheese158@gmail.com>
Date:   Thu Mar 28 19:31:59 2024 -0500

    Docs: adding games rework (#2892)

    * Docs: complete adding games.md rework

    * remove all the now unused images

    * review changes

    * address medic's review

    * address more comments

commit 9dc708978b
Author: Trevor L <80716066+TRPG0@users.noreply.github.com>
Date:   Thu Mar 28 18:26:58 2024 -0600

    Hylics 2: Fix invalid multiworld data, use `self.random` instead of `self.multiworld.random` (#3001)

    * Hylics 2: Fixes

    * Rewrite loop

commit 4391d1f4c1
Author: Bryce Wilson <gyroscope15@gmail.com>
Date:   Thu Mar 28 18:05:39 2024 -0600

    Pokemon Emerald: Fix opponents learning non-randomized TMs (#3025)

commit 5d9d4ed9f1
Author: black-sliver <59490463+black-sliver@users.noreply.github.com>
Date:   Fri Mar 29 01:01:31 2024 +0100

    SoE: update to pyevermizer v0.48.0 (#3050)

commit c97215e0e7
Author: Scipio Wright <scipiowright@gmail.com>
Date:   Thu Mar 28 17:23:37 2024 -0400

    TUNIC: Minor refactor of the vanilla_portals function (#3009)

    * Remove unused, change an if to an elif

    * Remove unused import

commit eb66886a90
Author: Alchav <59858495+Alchav@users.noreply.github.com>
Date:   Thu Mar 28 16:23:01 2024 -0500

    SC2: Don't Filter Excluded Victory Locations (#3018)

commit de860623d1
Author: Fabian Dill <Berserker66@users.noreply.github.com>
Date:   Thu Mar 28 22:21:56 2024 +0100

    Core: differentiate between unknown worlds and broken worlds in error message (#2903)

commit 74b2bf5161
Author: Bryce Wilson <gyroscope15@gmail.com>
Date:   Thu Mar 28 15:20:55 2024 -0600

    Pokemon Emerald: Exclude norman trainer location during norman goal (#3038)

commit 74ac66b032
Author: BadMagic100 <dempsey.sean@outlook.com>
Date:   Thu Mar 28 08:49:19 2024 -0700

    Hollow Knight: 0.4.5 doc revamp and default options tweaks (#2982)

    Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

commit 80d7ac4164
Author: Silvris <58583688+Silvris@users.noreply.github.com>
Date:   Thu Mar 28 09:41:32 2024 -0500

    KDL3: RC1 Fixes and Enhancement (#3022)

    * fix cloudy park 4 rule, zero deathlink message

    * remove redundant door_shuffle bool

    when generic ER gets in, this whole function gets rewritten. So just clean it a little now.

    * properly fix deathlink messages, fix fill error

    * update docs

commit 77311719fa
Author: Ziktofel <ziktofel@gmail.com>
Date:   Thu Mar 28 15:38:34 2024 +0100

    SC2: Fix HERC upgrades (#3044)

commit cfc1541be9
Author: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Date:   Thu Mar 28 15:19:32 2024 +0100

    Docs: Mention the "last received item index" paradigm in the network protocol docs (#2989)

    Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

commit 4d954afd9b
Author: Scipio Wright <scipiowright@gmail.com>
Date:   Thu Mar 28 10:11:20 2024 -0400

    TUNIC: Add link to AP plando guide to connection plando section of game page (#2993)

commit 17748a4bf1
Author: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
Date:   Thu Mar 28 10:00:10 2024 -0400

    Launcher, Docs: Update UI and Set-Up Guide to Reference Options  (#2950)

commit 9182fe563f
Author: Entropynines <163603868+Entropynines@users.noreply.github.com>
Date:   Thu Mar 28 06:56:35 2024 -0700

    README: Remove outdated information about launchers (#2966)

    Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

commit bcf223081f
Author: t3hf1gm3nt <59876300+t3hf1gm3nt@users.noreply.github.com>
Date:   Thu Mar 28 09:54:56 2024 -0400

    TLOZ: Fix markdown issue with game info page (#2985)

commit fa93488f3f
Author: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Date:   Thu Mar 28 09:46:00 2024 -0400

    Docs: Consistent naming for "connection plando" (#2994)

commit db15dd4bde
Author: chandler05 <66492208+chandler05@users.noreply.github.com>
Date:   Thu Mar 28 08:45:19 2024 -0500

    A Short Hike: Fix incorrect info in docs (#3016)

commit 01cdb0d761
Author: PoryGone <98504756+PoryGone@users.noreply.github.com>
Date:   Thu Mar 28 09:44:23 2024 -0400

    SMW: Update World Doc for v2.0 Features (#3034)

    Co-authored-by: Scipio Wright <scipiowright@gmail.com>

commit d0ac2b744e
Author: panicbit <panicbit@users.noreply.github.com>
Date:   Thu Mar 28 10:11:26 2024 +0100

    LADX: fix local and non-local instrument placement (#2987)

    * LADX: fix local and non-local instrument placement

    * change confusing variable name

commit 14f5f0127e
Author: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>
Date:   Thu Mar 28 04:42:35 2024 -0400

    Stardew Valley: Fix potential soft lock with vanilla tools and entrance randomizer + Performance improvement for vanilla tool/skills (#3002)

    * fix vanilla tool fishing rod requiring metal bars
    fix vanilla skill requiring previous level (it's always the same rule or more restrictive)

    * add test to ensure fishing rod need fish shop

    * fishing rod should be indexed from 0 like a mentally sane person would do.

    * fishing rod 0 isn't real, but it definitely can hurt you.

    * reeeeeeeee

commit cf133dde72
Author: Bryce Wilson <gyroscope15@gmail.com>
Date:   Thu Mar 28 02:32:27 2024 -0600

    Pokemon Emerald: Fix typo (#3020)

commit ca18121811
Author: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>
Date:   Thu Mar 28 04:27:49 2024 -0400

    Stardew Valley: Fix generation fail with SVE and entrance rando when Wizard Tower is in place of Sprite Spring (#2970)

commit 1d4512590e
Author: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Date:   Wed Mar 27 21:09:09 2024 +0100

    requirements.txt: _ instead of - to make PyCharm happy (#3043)

commit f7b415dab0
Author: agilbert1412 <alexgilbert@yahoo.com>
Date:   Tue Mar 26 19:40:58 2024 +0300

    Stardew valley: Game version documentation (#2990)

    Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

commit 702f006c84
Author: LiquidCat64 <74896918+LiquidCat64@users.noreply.github.com>
Date:   Tue Mar 26 07:31:36 2024 -0600

    CV64: Change all mentions of "settings" to "options" and fix a broken link (#3015)

commit 98ce8f8844
Author: Yussur Mustafa Oraji <N00byKing@hotmail.de>
Date:   Tue Mar 26 14:29:25 2024 +0100

    sm64ex: New Options API and WebHost fix (#2979)

commit ea47b90367
Author: Scipio Wright <scipiowright@gmail.com>
Date:   Tue Mar 26 09:25:41 2024 -0400

    TUNIC: You can grapple down here without the ladder, neat (#3019)

commit bf3856866c
Author: agilbert1412 <alexgilbert@yahoo.com>
Date:   Sun Mar 24 23:53:49 2024 +0300

    Stardew Valley: presets with some of the new available values for existing settings to make them more accurate (#3014)

commit c0368ae0d4
Author: Phaneros <31861583+MatthewMarinets@users.noreply.github.com>
Date:   Sun Mar 24 13:53:20 2024 -0700

    SC2: Fixed missing upgrade from custom tracker (#3013)

commit 36c83073ad
Author: Salzkorn <salzkitty@gmail.com>
Date:   Sun Mar 24 21:52:41 2024 +0100

    SC2 Tracker: Fix grouped items pointing at wrong item IDs (#2992)

commit 2b24539ea5
Author: Ziktofel <ziktofel@gmail.com>
Date:   Sun Mar 24 21:52:16 2024 +0100

    SC2 Tracker: Use level tinting to let the player know which level he has of Replenishable Magazine (#2986)

commit 7e904a1c78
Author: Ziktofel <ziktofel@gmail.com>
Date:   Sun Mar 24 21:51:46 2024 +0100

    SC2: Fix Kerrigan presence resolving when deciding which races should be used (#2978)

commit bdd498db23
Author: Alchav <59858495+Alchav@users.noreply.github.com>
Date:   Fri Mar 22 15:36:27 2024 -0500

    ALTTP: Fix #2290's crashes (#2973)

commit 355223b8f0
Author: PinkSwitch <52474902+PinkSwitch@users.noreply.github.com>
Date:   Fri Mar 22 15:35:00 2024 -0500

    Yoshi's Island: Implement New Game (#2141)

    Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>
    Co-authored-by: Alchav <59858495+Alchav@users.noreply.github.com>
    Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
    Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

commit aaa3472d5d
Author: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Date:   Fri Mar 22 21:30:51 2024 +0100

    The Witness: Fix seed bleed issue (#3008)

commit 96d93c1ae3
Author: chandler05 <66492208+chandler05@users.noreply.github.com>
Date:   Fri Mar 22 15:30:23 2024 -0500

    A Short Hike: Add option to customize filler coin count (#3004)

    Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

commit ca549df20a
Author: Silvris <58583688+Silvris@users.noreply.github.com>
Date:   Fri Mar 22 15:29:24 2024 -0500

    CommonClient: fix hint tab overlapping (#2957)

    Co-authored-by: Remy Jette <remy@remyjette.com>

commit 44988d430d
Author: Star Rauchenberger <fefferburbia@gmail.com>
Date:   Fri Mar 22 15:28:41 2024 -0500

    Lingo: Add trap weights option (#2837)

commit 11b32f17ab
Author: Danaël V <104455676+ReverM@users.noreply.github.com>
Date:   Fri Mar 22 12:46:14 2024 -0400

    Docs: replacing "setting" to "option" in world docs  (#2622)

    * Update contributing.md

    * Update contributing.md

    * Update contributing.md

    * Update contributing.md

    * Update contributing.md

    * Update contributing.md

    Added non-AP World specific information

    * Update contributing.md

    Fixed broken link

    * Some minor touchups

    * Update Contributing.md

    Draft for version with picture

    * Update contributing.md

    Small word change

    * Minor updates for conciseness, mostly

    * Changed all instances of settings to options in info and setup guides

    I combed through all world docs and swapped "setting" to "option" when this was refering to yaml options.
    I also changed a leftover "setting" in option.py

    * Update contributing.md

    * Update contributing.md

    * Update setup_en.md

    Woops I forgot one

    * Update Options.py

    Reverted changes regarding options.py

    * Update worlds/noita/docs/en_Noita.md

    Co-authored-by: Scipio Wright <scipiowright@gmail.com>

    * Update worlds/sc2wol/docs/en_Starcraft 2 Wings of Liberty.md

    revert change waiting for that page to be updated

    * Update worlds/witness/docs/setup_en.md

    * Update worlds/witness/docs/en_The Witness.md

    * Update worlds/soe/docs/multiworld_en.md

    Fixed Typo

    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

    * Update worlds/witness/docs/en_The Witness.md

    * Update worlds/adventure/docs/en_Adventure.md

    * Update worlds/witness/docs/setup_en.md

    * Updated Stardew valley to hopefully get rid of the merge conflicts

    * Didn't work :dismay:

    * Delete worlds/sc2wol/docs/setup_en.md

    I think this will fix the merge issue

    * Now it should work

    * Woops

    ---------

    Co-authored-by: Scipio Wright <scipiowright@gmail.com>
    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

commit 218cd45844
Author: Silvris <58583688+Silvris@users.noreply.github.com>
Date:   Fri Mar 22 03:02:38 2024 -0500

    APProcedurePatch: fix RLE/COPY incorrect sizing (#3006)

    * change class variables to instance variables

    * Update worlds/Files.py

    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

    * Update worlds/Files.py

    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

    * move required_extensions to tuple

    * fix missing tuple ellipsis

    * fix classvar mixup

    * rename tokens to _tokens. use hasattr

    * type hint cleanup

    * Update Files.py

    * check using isinstance instead

    * Update Files.py

    ---------

    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

commit 4196bde597
Author: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Date:   Thu Mar 21 16:38:36 2024 -0400

    Docs: Fixing special_range_names example (#3005)

commit 40f843f54d
Author: Star Rauchenberger <fefferburbia@gmail.com>
Date:   Thu Mar 21 11:00:53 2024 -0500

    Lingo: Minor game data fixes (#3003)

commit da333fbb0c
Author: GodlFire <46984098+GodlFire@users.noreply.github.com>
Date:   Thu Mar 21 09:52:16 2024 -0600

    Shivers: Adds missing logic rule for skull dial door location (#2997)

commit 43084da23c
Author: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Date:   Thu Mar 21 16:51:29 2024 +0100

    The Witness: Fix newlines in Witness option tooltips (#2971)

commit 14816743fc
Author: Scipio Wright <scipiowright@gmail.com>
Date:   Thu Mar 21 11:50:07 2024 -0400

    TUNIC: Shuffle Ladders option (#2919)

commit 30a0aa2c85
Author: Star Rauchenberger <fefferburbia@gmail.com>
Date:   Thu Mar 21 10:46:53 2024 -0500

    Lingo: Add item/location groups (#2789)

commit f4b7c28a33
Author: Silvris <58583688+Silvris@users.noreply.github.com>
Date:   Wed Mar 20 17:45:32 2024 -0500

    APProcedurePatch: hotfix changing class variables to instance variables (#2996)

    * change class variables to instance variables

    * Update worlds/Files.py

    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

    * Update worlds/Files.py

    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

    * move required_extensions to tuple

    * fix missing tuple ellipsis

    * fix classvar mixup

    * rename tokens to _tokens. use hasattr

    * type hint cleanup

    * Update Files.py

    * check using isinstance instead

    ---------

    Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

commit 12864f7b24
Author: chandler05 <66492208+chandler05@users.noreply.github.com>
Date:   Wed Mar 20 22:44:09 2024 +0100

    A Short Hike: Implement New Game (#2577)

commit db02e9d2aa
Author: LiquidCat64 <74896918+LiquidCat64@users.noreply.github.com>
Date:   Wed Mar 20 15:03:25 2024 -0600

    Castlevania 64: Implement New Game (#2472)

commit 32315776ac
Author: Jérémie Bolduc <16137441+Jouramie@users.noreply.github.com>
Date:   Wed Mar 20 16:57:45 2024 -0400

    Stardew Valley: Fix extended family legendary fishes being locations with fishsanity set to exclude legendary (#2967)

commit e9620bea77
Author: Magnemania <89949176+Magnemania@users.noreply.github.com>
Date:   Wed Mar 20 16:56:00 2024 -0400

    SM64: Goal Logic and Hint Bugfixes (#2886)

commit 183ca35bba
Author: qwint <qwint.42@gmail.com>
Date:   Wed Mar 20 08:39:37 2024 -0500

    CommonClient: Port Casting Bug (#2975)

commit fcaaa197a1
Author: TheLX5 <luisyuregi@gmail.com>
Date:   Wed Mar 20 05:56:19 2024 -0700

    SMW: Fixes for Bowser being defeatable on Egg Hunt and CI2 DC room access (#2981)

commit 8f7b63a787
Author: TheLX5 <luisyuregi@gmail.com>
Date:   Wed Mar 20 05:56:04 2024 -0700

    SMW: Blocksanity logic fixes (#2988)

commit 6f64bb9869
Author: Scipio Wright <scipiowright@gmail.com>
Date:   Wed Mar 20 08:46:31 2024 -0400

    Noita: Remove newline from option description so it doesn't look bad on webhost (#2969)

commit d0a9d0e2d1
Author: Bryce Wilson <gyroscope15@gmail.com>
Date:   Wed Mar 20 06:43:13 2024 -0600

    Pokemon Emerald: Bump required client version (#2963)

commit 94650a02de
Author: Silvris <58583688+Silvris@users.noreply.github.com>
Date:   Tue Mar 19 17:08:29 2024 -0500

    Core: implement APProcedurePatch and APTokenMixin (#2536)

    * initial work on procedure patch

    * more flexibility

    load default procedure for version 5 patches
    add args for procedure
    add default extension for tokens and bsdiff
    allow specifying additional required extensions for generation

    * pushing current changes to go fix tloz bug

    * move tokens into a separate inheritable class

    * forgot the commit to remove token from ProcedurePatch

    * further cleaning from bad commit

    * start on docstrings

    * further work on docstrings and typing

    * improve docstrings

    * fix incorrect docstring

    * cleanup

    * clean defaults and docstring

    * define interface that has only the bare minimum required
    for `Patch.create_rom_file`

    * change to dictionary.get

    * remove unnecessary if statement

    * update to explicitly check for procedure, restore compatible version and manual override

    * Update Files.py

    * remove struct uses

    * ensure returning bytes, add token type checking

    * Apply suggestions from code review

    Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

    * pep8

    ---------

    Co-authored-by: beauxq <beauxq@yahoo.com>
    Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

* Changes pot_completed_list to a instance variable instead of global.

Changes pot_completed_list to a instance variable instead of global. The global variable was unintentional and was causing missmatch in pre_fill which would cause generation error.

* Removing deprecated options getter

* Adds back fix from main branch

Adds back fix from main branch

* Removing messenger changes that somehow got on my branch?

Removing messenger changes that somehow got on my branch?

* Removing messenger changes that are somehow on the Shivers branch

Removing messenger changes that are somehow on the Shivers branch

* Still trying to remove Messenger changes on Shivers branch

Still trying to remove Messenger changes on Shivers branch

* Review comments addressed. Early lobby access set as default.

Review comments addressed. Early lobby access set as default.

* Review comments addressed

Review comments addressed

* Review comments addressed. Option for priority locations removed.

Option to have ixupi captures a priority has been removed and can be added again if Priority Fill is changed. See Issues #3467.

* Minor Change

Minor Change

* Fixed ID 10 T Error

Fixed ID 10 T Error

* Front door option added to slot data

Front door option added to slot data

* Add missing .value on slot data

Add missing .value on slot data

* Small change to slot data

Small change to slot data

* Small change to slot data

Why didn't this change get pushed github...

* Forgot list

Forgot list

---------

Co-authored-by: Kory Dondzila <korydondzila@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-07-31 17:32:17 +02:00
Aaron Wagener a05dbac55f
Core: Rework accessibility (#1481)
* rename locations accessibility to "full" and make old locations accessibility debug only

* fix a bug in oot

* reorder lttp tests to not override its overrides

* changed the wrong word in the dict

* :forehead:

* update the manual lttp yaml

* use __debug__

* update pokemon and messenger

* fix conflicts from 993

* fix stardew presets

* add that locations may be inaccessible to description

* use reST format and make the items description one line so that it renders correctly on webhost

* forgot i renamed that

* add aliases for back compat

* some cleanup

* fix imports

* fix test failure

* only check "items" players when the item is progression

* Revert "only check "items" players when the item is progression"

This reverts commit ecbf986145e6194aa99a39c481d8ecd0736d5a4c.

* remove some unnecessary diffs

* CV64: Add ItemsAccessibility

* put items description at the bottom of the docstring since that's it's visual order

* :

* rename accessibility reference in pokemon rb dexsanity

* make the rendered tooltips look nicer
2024-07-31 12:13:14 +02:00
Aaron Wagener 83521e99d9
Core: migrate item links out of main (#2914)
* Core: move item linking out of main

* add a test that item link option correctly validates

* remove unused fluff

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-07-31 12:04:21 +02:00
Jarno 1d19da0c76
Timespinner: migrate to new options api and correct random (#2485)
* Implemented new options system into Timespinner

* Fixed typo

* Fixed typo

* Fixed slotdata maybe

* Fixes

* more fixes

* Fixed failing unit tests

* Implemented options backwards comnpatibility

* Fixed option fallbacks

* Implemented review results

* Fixed logic bug

* Fixed python 3.8/3.9 compatibility

* Replaced one more multiworld option usage

* Update worlds/timespinner/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Updated logging of options replacement to include player name and also write it to spoiler
Fixed generation bug
Implemented review results

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-07-31 11:50:04 +02:00
Remy Jette 77e3f9fbef
WebHost: Fix NamedRange values clamping to the range (#3613)
If a NamedRange has a `special_range_names` entry outside the
`range_start` and `range_end`, the HTML5 range input will clamp the
submitted value to the closest value in the range.

These means that, for example, Pokemon RB's "HM Compatibility" option's
"Vanilla (-1)" option would instead get posted as "0" rather than "-1".

This change updates NamedRange to behave like TextChoice, where the
select element has a `name` attribute matching the option, and there is
an additional element to be able to provide an option other than the
select element's choices.

This uses a different suffix of `-range` rather than `-custom` that
TextChoice uses. The reason is we need some way to decide whether to use
the custom value or the select value, and that method needs to work
without JavaScript. For TextChoice this is easy, if the custom field is
empty use the select element. For NamedRange this is more difficult as
the browser will always submit *something*. My choice was to only use
the value from the range if the select box is set to "custom". Since
this only happens with JS as "custom' is hidden, I made the range hidden
under no-JS. If it's preferred, I could make the select box hidden
instead. Let me know.

This PR also makes the `js-required` class set `display: none` with
`!important` as otherwise the class wouldn't work on any rule that
had `display: flex` with more specificity than a single class.
2024-07-29 20:13:44 -04:00
Phaneros 954d728005
sc2: Removing unused dependency in requirements.txt (#3697)
* sc2: Removing unused dependency in requirements.txt

* sc2: Add missing newline in requirements.txt

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-07-29 23:09:51 +02:00
agilbert1412 80daa092a7
- Take shipsanity moss out of shipsanity crops (#3709) 2024-07-29 19:42:16 +02:00
Alchav fac72dbc20
FFMQ: Fix reset protection (#3710)
* Revert reset protection

* Fix reset protection

---------

Co-authored-by: alchav <alchav@jalchavware.com>
2024-07-29 19:40:58 +02:00
qwint e764da3dc6
HK: Options API updates, et al. (#3428)
* updates HK to consistently use world.random, use world.options, don't use world = self.multiworld, and remove some things from the logicMixin

* Update HK to new options dataclass

* Move completion condition helpers to Rules.py

* updates from review
2024-07-28 23:27:39 +02:00
CaitSith2 ab0903679c
Factorio: Fix ap-get-technology nil value crashes (#3517) 2024-07-28 20:57:10 +02:00
Star Rauchenberger 67f329b96f
Lingo: Add warpless connection between Hedge Maze and The Incomparable (#3703)
These areas are technically connected through The Observant, but the connection between The Observant and The Incomparable is marked as a warp because of the warp hallways leading up to The Observant's achievement panel. Creating separate entrances for The Incomparable is a simple workaround, and allows use of that connection during a pilgrimage.
2024-07-28 17:41:57 +02:00
Scipio Wright b273852512
Fix obvious typo (#3622) 2024-07-28 00:44:48 -04:00
Fabian Dill b77805e5ee
Fill: remove sweep_for_events(key_only=True) (#2239) 2024-07-28 01:32:25 +02:00
lilDavid 34141f8de0
SMZ3: Classify "nice" items as useful (#3683) 2024-07-27 23:19:09 +02:00
Scipio Wright e38f5d0a61
TUNIC: Update plando connection option call to use options API #3695 2024-07-27 23:17:59 +02:00
Star Rauchenberger 35ed0d4e19
Lingo: Fix Rhyme Room LEAP panel logic (#3699) 2024-07-27 23:17:34 +02:00
CookieCat e5c9b8ad0c
AHIT: Generation error fixes and some other bug fixes (#3663)
* duh

* Fuck it

* Major fixes

* a

* b

* Even more fixes

* New option - NoFreeRoamFinale

* a

* Hat Logic Fix

* Just to be safe

* multiworld.random to world.random

* KeyError fix

* Update .gitignore

* Update __init__.py

* Zoinks Scoob

* ffs

* Ruh Roh Raggy, more r-r-r-random bugs!

* 0.9b - cleanup + expanded logic difficulty

* Update Rules.py

* Update Regions.py

* AttributeError fix

* 0.10b - New Options

* 1.0 Preparations

* Docs

* Docs 2

* Fixes

* Update __init__.py

* Fixes

* variable capture my beloathed

* Fixes

* a

* 10 Seconds logic fix

* 1.1

* 1.2

* a

* New client

* More client changes

* 1.3

* Final touch-ups for 1.3

* 1.3.1

* 1.3.3

* Zero Jumps gen error fix

* more fixes

* Formatting improvements

* typo

* Update __init__.py

* Revert "Update __init__.py"

This reverts commit e178a7c0a6904ace803241cab3021d7b97177e90.

* init

* Update to new options API

* Missed some

* Snatcher Coins fix

* Missed some more

* some slight touch ups

* rewind

* a

* fix things

* Revert "Merge branch 'main' of https://github.com/CookieCat45/Archipelago-ahit"

This reverts commit a2360fe197e77a723bb70006c5eb5725c7ed3826, reversing
changes made to b8948bc4958855c6e342e18bdb8dc81cfcf09455.

* Update .gitignore

* 1.3.6

* Final touch-ups

* Fix client and leftover old options api

* Delete setup-ahitclient.py

* Update .gitignore

* old python version fix

* proper warnings for invalid act plandos

* Update worlds/ahit/docs/en_A Hat in Time.md

Co-authored-by: Danaël V. <104455676+ReverM@users.noreply.github.com>

* Update worlds/ahit/docs/setup_en.md

Co-authored-by: Danaël V. <104455676+ReverM@users.noreply.github.com>

* 120 char per line

* "settings" to "options"

* Update DeathWishRules.py

* Update worlds/ahit/docs/en_A Hat in Time.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* No more loading the data package

* cleanup + act plando fixes

* almost forgot

* Update Rules.py

* a

* Update worlds/ahit/Options.py

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* Options stuff

* oop

* no unnecessary type hints

* warn about depot download length in setup guide

* Update worlds/ahit/Options.py

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* typo

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* Update worlds/ahit/Rules.py

Co-authored-by: Ixrec <ericrhitchcock@gmail.com>

* review stuff

* More stuff from review

* comment

* 1.5 Update

* link fix?

* link fix 2

* Update setup_en.md

* Update setup_en.md

* Update setup_en.md

* Evil

* Good fucking lord

* Review stuff again + Logic fixes

* More review stuff

* Even more review stuff - we're almost done

* DW review stuff

* Finish up review stuff

* remove leftover stuff

* a

* assert item

* add A Hat in Time to readme/codeowners files

* Fix range options not being corrected properly

* 120 chars per line in docs

* Update worlds/ahit/Regions.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* Update worlds/ahit/DeathWishLocations.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* Remove some unnecessary option.class.value

* Remove data_version and more option.class.value

* Update worlds/ahit/Items.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* Remove the rest of option.class.value

* Update worlds/ahit/DeathWishLocations.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* review stuff

* Replace connect_regions with Region.connect

* review stuff

* Remove unnecessary Optional from LocData

* Remove HatType.NONE

* Update worlds/ahit/test/TestActs.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* fix so default tests actually don't run

* Improve performance for death wish rules

* rename test file

* change test imports

* 1000 is probably unnecessary

* a

* change state.count to state.has

* stuff

* starting inventory hats fix

* shouldn't have done this lol

* make ship shape task goal equal to number of tasksanity checks if set to 0

* a

* change act shuffle starting acts + logic updates

* dumb

* option groups + lambda capture cringe + typo

* a

* b

* missing option in groups

* c

* Fix Your Contract Has Expired being placed on first level when it shouldn't

* yche fix

* formatting

* major logic bug fix for death wish

* Update Regions.py

* Add missing indirect connections

* Fix generation error from chapter 2 start with act shuffle off

* a

* Revert "a"

This reverts commit df58bbcd998585760cc6ac9ea54b6fdf142b4fd1.

* Revert "Fix generation error from chapter 2 start with act shuffle off"

This reverts commit 0f4d441824af34bf7a7cff19f5f14161752d8661.

* bunch of fixes

* Update Regions.py

* Update __init__.py

* Update __init__.py

* Update __init__.py

* Update Regions.py

* Update worlds/ahit/__init__.py

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>

* Update __init__.py

* Update __init__.py

---------

Co-authored-by: Danaël V. <104455676+ReverM@users.noreply.github.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
Co-authored-by: Ixrec <ericrhitchcock@gmail.com>
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2024-07-27 19:16:52 +02:00
Exempt-Medic 6994f863e5
Core: Make excluded locations and priority locations excluded and remove unreachable code (#3424)
* Make excluded and priority locations excluded

* Only pass on KeyError

* Alternative/Clearer format
2024-07-26 17:51:55 +02:00
Jérémie Bolduc 9d36ad0df2
Stardew Valley: Properly support Universal Tracker (#3630)
* save the seed in slot data to reuse it in UT

* add logging when seed is missing

* add UT test and fix bundle test

* self review

* run UT test on allsanity+mod so it's more meaningfull
2024-07-26 11:33:14 +02:00
Star Rauchenberger cc22161644
Lingo: Add panels mode door shuffle (#3163)
* Created panels mode door shuffle

* Added some panel door item names

* Remove RUNT TURN panel door

Not really useful.

* Fix logic with First SIX related stuff

* Add group_doors to slot data

* Fix LEVEL 2 behavior with panels mode

* Fixed unit tests

* Fixed duplicate IDs from merge

* Just regenerated new IDs

* Fixed duplication of color and door group items

* Removed unnecessary unit test option

* Fix The Seeker being achievable without entrance door

* Fix The Observant being achievable without locked panels

* Added some more panel doors

* Added Progressive Suits Area

* Lingo: Fix Basement access with THE MASTER

* Added indirect conditions for MASTER-blocked entrances

* Fixed Incomparable achievement access

* Fix STAIRS panel logic

* Fix merge error with good items

* Is this clearer?

* DREAD and TURN LEARN

* Allow a weird edge case for reduced locations

Panels mode door shuffle + grouped doors + color shuffle + pilgrimage enabled is exactly the right number of items for reduced locations. Removing color shuffle also allows for disabling pilgrimage, adding sunwarp locking, or both, with a couple of locations left over.

* Prevent small sphere one on panels mode

* Added shuffle_doors aliases for old options

* Fixed a unit test

* Updated datafile

* Tweaked requirements for reduced locations

* Added player name to OptionError messages

* Update generated.dat
2024-07-26 10:53:11 +02:00
Star Rauchenberger d030a698a6
Lingo: Changed minimum progression requirement (#3672) 2024-07-25 23:09:37 +02:00
Exempt-Medic b6e5223aa2
Docs: Expanding on the answers in the FAQ (#3690)
* Expand on some existing answers

* Oops

* Sphere "one"

* Removing while

* Update docs/apworld_dev_faq.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2024-07-25 23:02:25 +02:00
qwint 79843803cf
Docs: Add header to FAQ doc referencing other relevant docs (#3692)
* Add header to FAQ doc referencing other relevant docs

* Update docs/apworld_dev_faq.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update docs/apworld_dev_faq.md

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2024-07-25 23:01:22 +02:00
Tsukino 5fb1ebdcfd
Docs: Add Swedish Guide for Pokemon Emerald (#3252)
* Docs: Add Swedish Guide for Pokemon Emerald

Swedish Translation

* v2

some proof reading & clarification changes

* v3

* v4

* v5

typo

* v6

* Update worlds/pokemon_emerald/docs/setup_sv.md

Co-authored-by: Bryce Wilson <gyroscope15@gmail.com>

* Update worlds/pokemon_emerald/docs/setup_sv.md

Co-authored-by: Bryce Wilson <gyroscope15@gmail.com>

* v7

Tried to reduce the length of lines, this should still convey the same message/meaning

* typo

* v8

Removed Leading/Trailing Spaces

* typo v2

* Added a couple of full stops.

* lowercase typos

* Update setup_sv.md

* Apply suggestions from code review

Co-authored-by: Bryce Wilson <gyroscope15@gmail.com>

---------

Co-authored-by: Bryce Wilson <gyroscope15@gmail.com>
Co-authored-by: bittersweetrin <chandraherbozo@gmail.com>
2024-07-25 09:30:23 +02:00
CookieCat b019485944
AHIT: Update Setup Guide (#3647) 2024-07-25 09:27:22 +02:00
Witchybun 205ca7fa37
Stardew Valley: Fix Daggerfish, Cropsanity; Move Some Rules to Content Packs; Add Missing Shipsanity Location (#3626)
* Fix logic bug on daggerfish

* Make new region for pond.

* Fix SVE logic for crops

* Fix Distant Lands Cropsanity

* Fix failing tests.

* Reverting removing these for now.

* Fix bugs, add combat requirement

* convert str into tuple directly

* add ginger island to mod tests

* Move a lot of mod item logic to content pack

* Gut the rules from DL while we're at it.

* Import nuke

* Fix alecto

* Move back some rules for now.

* Move archaeology rules

* Add some comments why its done.

* Clean up archaeology and fix sve

* Moved dulse to water item class

* Remove digging like worms for now

* fix

* Add missing shipsanity location

* Move background names around or something idk

* Revert ArchaeologyTrash for now

---------

Co-authored-by: Jouramie <jouramie@hotmail.com>
2024-07-25 09:22:46 +02:00
black-sliver 8949e21565
settings: safer writing (#3644)
* settings: clean up imports

* settings: try to use atomic rename

* settings: flush, sync and validate new yaml

before replacing the old one

* settings: add test for Settings.save
2024-07-25 09:10:36 +02:00
qwint deae524e9b
Docs: add a living faq document for sharing dev solutions (#3156)
* adding one faq :)

* adding another faq that links to the relevant file

* add lined line breaks between questions and lower the heading size of the question so sub-divisions can be added later

* missed some newlines

* updating best practice filler method

* add note about get_filler_item_name()

* updates to wording from review

* add section to CODEOWNERS for maintainers of this doc

* use underscores to reference the file easier in CODEOWNERS

* update link to be direct and filter to function name
2024-07-25 09:05:04 +02:00
qwint 496f0e09af
CommonClient: forget password when disconnecting (#3641)
* makes the kivy connect button do the same username forgetting that /connect does to fix an issue where losing connection would make you unable to connect to a different server

* extract duplicate code

* per request, adds handling on any disconnect to forget the saved password as to not leak it to other servers

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-07-25 08:21:51 +02:00
agilbert1412 f34da74012
Stardew Valley: Make Fairy Dust a Ginger Island only item and location (#3650) 2024-07-25 06:13:16 +02:00
Alchav 94e6e978f3
Pokémon R/B: Also fix Rt 4 Hidden Item (#3668)
Co-authored-by: alchav <alchav@jalchavware.com>
2024-07-25 06:07:20 +02:00
Silent 697f749518
TUNIC: Missing slot data bugfix (#3628)
* Fix certain items not being added to slot data

* Change where items get added to slot data
2024-07-25 06:06:45 +02:00
qwint 2307694012
HK: fix remove issues failing collect/remove test (#3667) 2024-07-25 03:08:58 +02:00
Exempt-Medic b23c120258
Subnautica: Fix deprecated option getting (#3685) 2024-07-24 22:17:43 +02:00
Silent ea1bb8d927
TUNIC: Missing slot data bugfix (#3628)
* Fix certain items not being added to slot data

* Change where items get added to slot data
2024-07-24 14:37:18 +02:00
Star Rauchenberger e714d2e129
Lingo: Add option to prevent shuffling postgame (#3350)
* Lingo: Add option to prevent shuffling postgame

* Allow roof access on door shuffle

* Fix broken unit test

* Simplified THE END edge case

* Revert unnecessary change

* Review comments

* Fix mastery unit test

* Update generated.dat

* Added player's name to error message
2024-07-24 14:34:51 +02:00
JKLeckr 878d5141ce
Project: Add .code-workspace wildcard to gitignore 2024-07-24 14:08:16 +02:00
Ladybunne 1852287c91
LADX: Add an item group for instruments (#3666)
* Add an item group for LADX instruments

* Update worlds/ladx/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Fix indent depth

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-07-24 14:07:07 +02:00
t3hf1gm3nt 8756f48e46
[TLOZ]: Fix determinism / Add Location Name Groups / Remove Level 9 Junk Fill (#3670)
* [TLOZ]: Fix determinism / Add Location Name Groups / Remove Level 9 Junk Fill

Axing the final uses of world.multiworld.random that were missed before, hopefully fixing the determinism issue brought up in Issue #3664 (at least on TLOZ's end, leaving SMZ3 alone). Also adding location name groups finally, as well as axing the Level 9 Junk Fill because with the new location name groups players can choose to exclude Level 9 with exclude locations instead.

* location name groups

* add take any item and sword cave location name groups

* use sets like you're supposed to, silly
2024-07-24 14:00:16 +02:00
agilbert1412 ff680b26cc
DLC Quest: Add options presets to DLC Quest (#3676)
* - Add options presets to DLC Quest

* - Removed unused import

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-07-24 13:49:28 +02:00
JaredWeakStrike 29a0b013cb
KH2: Hotfix update for game verison 1.0.0.9 (#3534)
* update the addresses hopefully

* todo

* update address for steam and epic

* oops

* leftover hard address

* made auto tracking say which version of the game

* not needed anymore since they were updated
2024-07-24 13:47:19 +02:00
Alchav e7dbfa7fcd
FFMQ: Efficiency Improvement and Use New Options Methods (#2767)
* FFMQ Efficiency improvement and use new options methods

* Hard check for 0x01 game status

* Fixes

* Why were Mac's Ship entrance hints excluded?

* Two remaining per_slot_randoms purged

* reformat generate_early

* Utils.parse_yaml
2024-07-24 13:46:14 +02:00
agilbert1412 ad5089b5a3
DLC Quest - Add option groups to DLC Quest (#3677)
* - Add option groups to DLC Quest

* - Slight reorganisation

* - Add type hint
2024-07-24 13:36:41 +02:00
NewSoupVi dc50444edd
The Witness: Small naming inconsistencies (#3618) 2024-07-24 13:13:41 +02:00
Silent ed4ad386e8
TUNIC: Add setting to disable local spoiler to host yaml (#3661)
* Add TunicSettings class for host yaml options

* Update __init__.py

* Update worlds/tunic/__init__.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Use self.settings

* Remove unused import

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2024-07-23 09:04:24 +02:00
Star Rauchenberger 5188375736
Lingo: Add pilgrimage logic through Starting Room (#3654)
* Lingo: Add pilgrimage logic through Starting Room

* Added unit test

* Reverse order of two doors in unit test

* Remove print statements from TestPilgrimage

* Update generated.dat
2024-07-23 08:34:47 +02:00
Star Rauchenberger 9c2933f803
Lingo: Fix Early Color Hallways painting in pilgrimages (#3645) 2024-07-23 00:45:49 +02:00
Scipio Wright b840c3fe1a
TUNIC: Move 3 locations to Quarry Back (#3649)
* Move 3 locations to Quarry Back

* Change the non-er region too
2024-07-23 00:43:41 +02:00
agilbert1412 c12d3dd6ad
Stardew valley: Fix Queen of Sauce Cookbook conditions (#3651)
* - Extracted walnut logic to a Mixin so it can be used in content pack requirements

* - Add 100 walnut requirements to the Queen of Sauce Cookbook

* - Woops a file wasn't added to previous commits

* - Make the queen of sauce cookbook a ginger island only thing, due to the walnut requirement

* - Moved the book in the correct content pack

* - Removed an empty class that I'm not sure where it came from
2024-07-23 00:36:42 +02:00
Trevor L f7989780fa
Bomb Rush Cyberfunk: Fix final graffiti location being unobtainable (#3669) 2024-07-22 09:17:34 +02:00
agilbert1412 e59bec36ec
Stardew Valley: Add gourmand frog rules for completing his tasks sequentially (#3652) 2024-07-22 08:32:40 +02:00
agilbert1412 48a0fb05a2
Stardew Valley: Removed Stardrop Tea from Full Shipment (#3655) 2024-07-22 01:52:44 +02:00
chandler05 12f1ef873c
A Short Hike: Fix Boat Rental purchase being incorrectly calculated (#3639) 2024-07-22 01:47:46 +02:00
Rensen3 d7d4565429
YGO06: fixes non-deterministic bug by changing sets to lists (#3674) 2024-07-22 01:27:10 +02:00
qwint 7039b17bf6
CommonClient: fix bug when using Connect button without a disconnect (#3609)
* makes the kivy connect button do the same username forgetting that /connect does to fix an issue where losing connection would make you unable to connect to a different server

* extract duplicate code
2024-07-22 01:12:11 +02:00
Jérémie Bolduc 34e7748f23
Stardew Valley: Make sure number of month in time logic is a int to improve performance by ~20% (#3665)
* make sure number of month is actually a int

* improve rule explain like in pr

* remove redundant if in can_complete_bundle

* assert number is int so cache is not bloated
2024-07-20 21:24:24 +02:00
gurglemurgle5 e33a9991ef
CommonClient: Escape markup sent in chat messages (#3659)
* escape markup in uncolored text

* Fix comment to allign with style guide

Fixes the comment so it follows the style guide, along with making it
better explain the code.

* Make more concise
2024-07-19 08:37:59 +02:00
black-sliver 4d1507cd0e
Core: Update cx_freeze to 7.2.0 and freeze it (#3648)
supersedes ArchipelagoMW/Archipelago#3405
2024-07-18 00:49:59 +02:00
Fabian Dill 7b39b23f73
Subnautica: increase minimum client version (#3657) 2024-07-17 22:33:51 +02:00
Sunny Bat 925e02dca7
Raft: Move to new Options API (#3587) 2024-07-15 15:09:02 +02:00
CookieCat e76d32e908
AHIT: Fix act shuffle test fail (#3522) 2024-07-14 14:17:05 +02:00
dennisw100 08a36ec223
Undertale: Fixed output location of the patched game in UndertaleClient.py (#3418)
* Update UndertaleClient.py Fixed output location of the patched game

Fixed the error that when the client is opened outside of the archipelago folder, the patched folder would be created in there which on windows ends up trying to create it in the system32 folder

Bug Report: https://discord.com/channels/731205301247803413/1148330675452264499/1237412436382973962

* Undertale: removed unnecessary wrapping in UndertaleClient.py

I did not know os.path.join was unnecessary in this case the more you know.
2024-07-14 14:11:52 +02:00
Bryce Wilson 48dc14421e
Pokemon Emerald: Fix logic for coin case location (#3631) 2024-07-14 14:05:50 +02:00
black-sliver 948f50f35d
customserver: fix minor memory leak (#3636)
Old code keeps ref to last started room's task and thus never fully cleans it up.
2024-07-14 13:56:56 +02:00
black-sliver 187f9dac94
customserver: preemtively run GC before starting room (#3637)
GC seems to be lazy.
2024-07-14 13:56:27 +02:00
Scipio Wright eaec41d885
TUNIC: Fix event region for Quarry fuse (#3635) 2024-07-11 22:44:29 +02:00
Doug Hoskisson 1e3a4b6db5
Zillion: more rooms added to map_gen option (#3634) 2024-07-10 23:11:47 -07:00
Alchav 8c86139066
ALTTP: Bombable Wall to Crystaroller Room Logic (#3627) 2024-07-10 17:15:29 +02:00
black-sliver c96c554dfa
Tests, WebHost: add tests for host_room and minor cleanup (#3619)
* Tests, WebHost: move out setUp and fix typing in api_generate

Also fixes a typo
and changes client to be per-test rather than a ClassVar

* Tests, WebHost: add tests for display_log endpoint

* Tests, WebHost: add tests for host_room endpoint

* Tests, WebHost: enable Flask DEBUG mode for tests

This provides the actual error if a test raised an exception on the server.

* Tests, WebHost: use user_path for logs

This is what custom_server does now.

* Tests, WebHost: avoid triggering security scans
2024-07-07 16:51:10 +02:00
agilbert1412 9b22458f44
Stardew Valley 6.x.x: The Content Update (#3478)
Focus of the Update: Compatibility with Stardew Valley 1.6 Released on March 19th 2024
This includes randomization for pretty much all of the new content, including but not limited to
- Raccoon Bundles
- Booksanity
- Skill Masteries
- New Recipes, Craftables, Fish, Maps, Farm Type, Festivals and Quests

This also includes a significant reorganisation of the code into "Content Packs", to allow for easier modularity of various game mechanics between the settings and the supported mods. This improves maintainability quite a bit.

In addition to that, a few **very** requested new features have been introduced, although they weren't the focus of this update
- Walnutsanity
- Player Buffs
- More customizability in settings, such as shorter special orders, ER without farmhouse
- New Remixed Bundles
2024-07-07 15:04:25 +02:00
NewSoupVi f99ee77325
The Witness: Add some unit tests (#3328)
* Add hidden early symbol item option, make some unit tests

* Add early symbol item false to the arrows test

* I guess it's not an issue

* more tests

* assertEqual

* cleanup

* add minimum symbols test for all 3 modes

* Formatting

* Add more minimal beatability tests

* one more for the road

* I HATE THIS AAAAAAAAAAAHHHHHHHHHHH WHY DID WE GO WITH OPTIONS

* loiaqeäsdhgalikSDGHjasDÖKHGASKLDÖGHJASKLJGHJSAÖkfaöslifjasöfASGJÖASDLFGJ'sklgösLGIKsdhJLGÖsdfjälghklDASFJghjladshfgjasdfälkjghasdöLfghasd-kjgjASDLÖGHAESKDLJGJÖsdaLGJHsadöKGjFDSLAkgjölSÄDghbASDFKGjasdLJGhjLÖSDGHLJASKDkgjldafjghjÖLADSFghäasdökgjäsadjlgkjsadkLHGsaDÖLGSADGÖLwSdlgkJLwDSFÄLHBJsaöfdkHweaFGIoeWjvlkdösmVJÄlsafdJKhvjdsJHFGLsdaövhWDsköLV-ksdFJHGVöSEKD

* fix imports (within apworld needs to be relative)

* Update worlds/witness/options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Sure

* good suggestion

* subtest

* Add some EP shuffle unit tests, also an explicit event-checking unit test

* add more tests yay

* oops

* mypy

* Update worlds/witness/options.py

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

* Collapse into one test :(

* More efficiency

* line length

* More collapsing

* Cleanup and docstrings

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2024-07-06 13:40:55 +02:00
jamesbrq bfac100567
MLSS: Fix for missing cutscene trigger 2024-07-05 22:54:35 +02:00
Scipio Wright e7a8e195e6
TUNIC: Use fewer parameters in helper functions (#3356)
* Clean these functions up, get the hell out of here 5 parameter function

* Clean up a bunch of rules that no longer need to be multi-lined since the functions are shorter

* Clean up some range functions

* Update to use world instead of player like Vi recommended

* Fix merge conflict

* Fix after merge
2024-07-05 22:50:12 +02:00
Louis M 4054a9f15f
Aquaria: Renaming some locations for consistency (#3533)
* Change 'The Body main area' by 'The Body center area' for consistency

* Renaming some locations for consistency

* Adding a line for standard

* Replacing Cathedral by Mithalas Cathedral and addin Blind goal option

* Client option renaming for consistency

* Fix death link not working

* Removing death link from the option to put it client side

* Changing Left to Right
2024-07-05 22:40:26 +02:00
Phaneros ca76628813
sc2: Fixing typo in itemgroups.py causing spurious item groups with 2 letters chopped off (#3612) 2024-07-05 22:37:32 +02:00
Scipio Wright d4d0a3e945
TUNIC: Make the shop checks require a sword 2024-07-05 22:36:55 +02:00
Scipio Wright 315e0c89e2
Docs: Lastest -> Latest (#3616) 2024-07-03 18:13:16 +02:00
Remy Jette f6735745b6
Core: Fix !remaining (#3611) 2024-07-03 15:39:08 +02:00
Doug Hoskisson 50f7a79ea7
Zillion: new map generation feature (#3604) 2024-07-02 19:32:01 -07:00
NewSoupVi 95110c4787
The Witness: Fix door shuffle being completely broken 2024-07-03 00:34:17 +02:00
NewSoupVi 93617fa546
The Witness: mypy compliance (#3112)
* Make witness apworld mostly pass mypy

* Fix all remaining mypy errors except the core ones

* I'm a goofy stupid poopoo head

* Two more fixes

* ruff after merge

* Mypy for new stuff

* Oops

* Stricter ruff rules (that I already comply with :3)

* Deprecated ruff thing

* wait no i lied

* lol super nevermind

* I can actually be slightly more specific

* lint
2024-07-02 23:59:26 +02:00
black-sliver b6925c593e
WebHost: Log: handle FileNotFoundError (#3603) 2024-07-02 01:03:55 +02:00
Emily 401606e8e3
Docs: Clarify docs for `create_items` stage (#3600)
* Clarify docs re: `create_items` stage

* adjust wording after feedback

* adjust wording after more feedback
2024-07-01 23:34:06 +02:00
black-sliver e95bb5ea56
WebHost: Better host room (#3496)
* add Range= to log, making responses a lot smaller for massive rooms
* switch xhr to fetch
* post the form using fetch if possible
  * also refresh log faster while waiting for command echo / response
  * do not follow redirect, saving a request
  * do not post empty body
* smooth-scroll the log view
* paste the log into the div when loading the HTML (up to 1MB, rest will be `fetch`ed)
* fix duplicate charset in display_log response
2024-07-01 21:47:49 +02:00
Silvris 52a13d38e9
Tests: fix error reporting in test_default_all_state_can_reach_everything (#3601) 2024-07-01 20:47:40 +02:00
Scipio Wright 31bd5e3ebc
OOT: Add keys item_name_group (#3218)
* Add keys item_name_group

* Pep8ify

* Capitalizing Keys cause Bottles is capitalized, also putting it in the clearly marked hint groups area
2024-06-30 01:19:36 +02:00
Sunny Bat 192f1b3fae
Update Raft option text, setup guide text (#3272)
* Update Raft option text, setup guide

* Address comments

* Address PR comments

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-06-30 01:18:09 +02:00
Silent 55cb81d487
TUNIC: Update victory condition (#3579)
* Add hero relics to victory condition

* Update __init__.py

* Remove unneeded local variables for options

* Use has_group_unique

* fix spacing
2024-06-30 01:17:00 +02:00
Justus Lind 2424fb0c5b
Muse Dash: 6th Anniversary Song update (#3593)
* 6th Anniversary Update songs.

* Forgot to fix the name of Heartbeat.
2024-06-30 01:15:13 +02:00
Mrks 6191ff4b47
LADX: Fixed Display Names In Options Page (#3584)
* Fixed option group display names.

* Fixed display names for -at the moment- unused options.
2024-06-30 01:14:39 +02:00
Justus Lind 1c817e1eb7
Muse Dash: Update installation guides to recommend installing v0.6.1. (#3594)
* Update installation guides to recommend installing v0.6.1.

* Fix spanish spacing.

* Apply spanish changes.
2024-06-30 01:13:00 +02:00
Fabian Dill d4c00ed267
CommonClient: fix /received with items from Server (#3597) 2024-06-29 03:00:32 +02:00
Ziktofel e07a2667ae
SC2 Tracker: Migrate icons away from sc2legacy (#3595) 2024-06-27 14:02:03 +02:00
Scipio Wright b8f78af506
TUNIC: Fix minor logic bug in upper Zig (#3576)
* Add note about bushes to logic section of readme

* Fix missing logic on bridge switch chest in upper zig

* Revise upper zig rule change to account for ER
2024-06-27 14:01:35 +02:00
Scipio Wright 77304a8743
TUNIC: Update game info page with more tips (#3591)
* More minor updates to game info page

* Fix grammar
2024-06-27 13:00:20 +02:00
black-sliver 5882ce7380
Various worlds: Fix more absolute world imports (#3510)
* Adventure: remove absolute imports

* Alttp: remove absolute imports (all but tests)

* Aquaria: remove absolute imports in tests

running tests from apworld may fail (on 3.8 and maybe in the future) otherwise

* DKC3: remove absolute imports

* LADX: remove absolute imports

* Overcooked 2: remove absolute imports in tests

running tests from apworld may fail otherwise

* Rogue Legacy: remove absolute imports in tests

running tests from apworld may fail otherwise

* SC2: remove absolute imports

* SMW: remove absolute imports

* Subnautica: remove absolute imports in tests

running tests from apworld may fail otherwise

* Zillion: remove absolute imports in tests

running tests from apworld may fail otherwise
2024-06-27 08:51:27 +02:00
PinkSwitch 6c54b3596b
Yoshi's Island: Fix client giving victory randomly (#3586)
* Create d

* Create d

* Delete worlds/mariomissing/d

* Delete mariomissing directory

* Create d

* Add files via upload

* Delete worlds/mariomissing/d

* Delete worlds/mariomissing directory

* Add files via upload

* Delete worlds/sai2 directory

* fix dumb client bug
2024-06-26 13:19:16 +02:00
Alchav 07dd8f0671
LTTP: Add Missing Blind's Cell rule (#3589) 2024-06-25 20:15:51 +02:00
Remy Jette 935c94dc80
Installer: Fix .apworld registration (#3588) 2024-06-25 20:15:12 +02:00
Fabian Dill 1ab1aeff15
Core: update required_server_version to 0.5.0 (#3580) 2024-06-23 07:50:00 +02:00
Silvris 5ca31533dc
Tests: give seed on default tests and fix execnet error (#3520)
* output seed of default tests

* test execnet fix

* try failing with interpolated string

* Update bases.py

* try without tryexcept

* Update bases.py

* Update bases.py

* remove fake exception

* fix indent

* actually fix the execnet issue

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-06-22 21:00:15 +02:00
Mrks 60a26920e1
LADX: Probably fix generation error that palex had 2024-06-22 19:32:10 +02:00
StripesOO7 d00abe7b8e
OOT: Adds Options to slot_data for poptracker-pack (#3570)
* Add imo all needed options to fill_slot_data that are worth tracking in the poptracker pack. This is aimed at providing information for the oot poptracker-pack for autofilling of settings within this pack.

* cap line length at 120 and reorganize list

---------

Co-authored-by: StripesOO7 <54711792+StripeesOO7@users.noreply.github.com>
2024-06-22 13:50:20 +02:00
Mewlif 40c9dfd3bf
Undertale: Fixes a major logic bug, and updates Undertale to use the new Options API (#3528)
* Updated the options definitions to the new api

* Fixed the wrong base class being used for UndertaleOptions

* Undertale: Added get_filler_item_name to Undertale, changed multiworld.per_slot_randoms to self.random, removed some unused imports in options.py, and fixed rules.py still using state.multiworld instead of world.options, and simplified the set_completion_rules function in rules.py

* Undertale: Fixed it trying to add strings to the finished item pool

* fixed 1000g item not being in the key items pool for Undertale

* Removed ".copy()" for the junk_weights, reformatted the requested lines to have less new lines, and changed "itempool += [self.create_filler()]" to "itempool.append(self.create_filler())"
2024-06-21 18:21:46 +02:00
Fabian Dill ce37bed7c6
WebHost: fix accidental robots.txt capture (#3502) 2024-06-21 14:54:19 +02:00
Justus Lind 4f514e5944
Muse Dash: Song name change (#3572)
* Change the song name of the removed song to the one replacing it.

* Make it not part of Streamable songs for now.
2024-06-20 13:54:38 +02:00
Aaron Wagener f515a085db
The Messenger: Fix missing rules for Double Swing Saws (#3562)
* The Messenger: Fix missing rules for Double Swing Saws

* i put it in the wrong dictionary

* remove unnecessary call
2024-06-19 16:20:47 +02:00
eudaimonistic 903a0bab1a
Docs: Change setup_en.md to use Latest releases page (#3543)
* Change setup_en.md to use Latest releases page

Really simple change to point users to the Latest release page instead of the Releases page.  Saw a user accidentally download 0.3.6 because it was the last item on the page (they're accustomed to scrolling down to the bottom of the page in GitHub for the Assets section), and this change prevents that outright.

* Update setup_en.md

Rewrite text and link to restore semantic compatibility.
2024-06-19 16:12:25 +02:00
Kaito Sinclaire 9bb3947d7e
Doom 2, Heretic: fix missing items (Doom2 Megasphere, Heretic Torch) (#3561)
for doom 2, some of the armor and health weights were nudged down
to compensate for the addition of the megasphere

for heretic, the torch was just added without changing anything else,
as I felt doing so would negatively impact the distribution of
artifacts (and personally I already feel there's too few in a game)
2024-06-19 12:59:10 +02:00
Mrks 240d1a3bbf
LADX: Adding 'Option Groups' to the player options page. (#3560)
* Adding 'Option Groups' to the LADX player options page.

* Moved 'Miscellaneous' group to the logic effecting groups.
2024-06-19 08:40:10 +02:00
Kory Dondzila b6191ff7ca
Shivers: Adds missing indirect conditions. (#3558)
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-06-18 05:10:54 +02:00
Scipio Wright 19d00547c2
TUNIC: Add note about bushes to logic section of game info page (#3555)
* Add note about bushes to logic section of readme

* Update worlds/tunic/docs/en_TUNIC.md

Co-authored-by: Silent <110704408+silent-destroyer@users.noreply.github.com>

---------

Co-authored-by: Silent <110704408+silent-destroyer@users.noreply.github.com>
2024-06-18 04:51:54 +02:00
chesslogic 67a0a04917
Tests: minor: update tests base for Options API (#2516)
* update tests for Options API

* The actual "bug"

* resolve qwint's comment from 3 months ago
2024-06-18 04:49:26 +02:00
Star Rauchenberger af213c9e5d
LADX: Converted to new options API (+other small refactors) (#3542)
* Refactored various things

* Renamed hidden variable in dungeon item shuffle block

* Fixed LADXRSettings initialization

* Rename ladxr_options -> ladxr_settings

* Remove unnecessary int cast

* Update worlds/ladx/LADXR/generator.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-06-18 04:48:15 +02:00
Zach Parks 898509e7ee
CODEOWNERS: Remove @zig-for as world maintainer for LADX. (#3525)
Per request: https://discord.com/channels/731205301247803413/1214608557077700720/1250714693136547920
2024-06-16 05:38:08 -05:00
Zach Parks 1f685b4272
CommonClient: Use lookup_in_game instead of lookup_in_slot in case of own-game name lookup when disconnected from server. (#3514) 2024-06-16 05:37:05 -05:00
Scipio Wright c622240730
Tunc: Update plando connections description (#3545) 2024-06-16 05:02:48 +02:00
Mrks 1d314374d7
LADX: Moved ROM requirement from generate_output to stage_assert_generate. (#3540)
Co-authored-by: Mrks <markus.burmeister@mburm.de>
2024-06-16 04:31:32 +02:00
palex00 753eb8683f
Pokemon Red/Blue: Replaces link to R&B Poptracker with a new one (#3516)
* Update setup_en.md

* Update setup_es.md
2024-06-16 04:10:50 +02:00
Fabian Dill e8542b8acd
Generate: split ERmain out of main (#3515) 2024-06-16 03:27:06 +02:00
NewSoupVi 2a11d610b6
The Witness: Fix Shuffle Postgame always thinking it's Challenge Victory (#3504)
* Fix postgame thinking it's the wrong panel

* Also don't have a default value for it so it doesn't happen again
2024-06-16 01:56:20 +02:00
coveleski 92023a2cb5
Pokemon RB: Add new options to slot_data (#3538)
Added require_pokedex, blind_trainers, and area_1_to_1 mapping, which would be helpful to the poptracker packs to accurately reflect the checks available to players.
2024-06-16 01:55:52 +02:00
Fabian Dill df94271d30
LttP: fix single-player no-logic generation (#3454) 2024-06-15 19:18:26 +02:00
Bryce Wilson 0354315c22
Pokemon Emerald: Remove README (#3532) 2024-06-15 04:52:01 +02:00
Star Rauchenberger e796f0ae64
Core: Expose option aliases (#3512) 2024-06-15 04:50:26 +02:00
Natalie Weizenbaum c61505baf6
WebHost/Core/Lingo: Render option documentation as reStructuredText in the WebView (#3511)
* Render option documentation as reStructuredText in the WebView

This means that options can use the standard Python documentation
format, while producing much nicer-looking documentation in the
WebView with things like emphasis, lists, and so on.

* Opt existing worlds out of rich option docs

This avoids breaking the rendering of existing option docs which were
written with the old plain text rendering in mind, while also allowing
new options to default to the rich text rendering instead.

* Use reStructuredText formatting for Lingo Options docstrings

* Disable raw and file insertion RST directives

* Update doc comments per code review

* Make rich text docs opt-in

* Put rich_text_options_doc on WebWorld

* Document rich text API

* Code review

* Update docs/options api.md

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

* Update Options.py

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>

---------

Co-authored-by: Chris Wilson <chris@legendserver.info>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2024-06-14 18:53:42 -04:00
Fabian Dill 3972b1b257
Options: fix yaml export corner case (#3529) 2024-06-15 00:48:49 +02:00
black-sliver 1fe3d842c8
CI: Install specific inno version (#3526)
* CI: Install specific inno version

* great mobile dev experience

* maybe this

* really don't enjoy PS

* Anothet attempt

* maybe fix log

* slowly going mad

* fml

* allow downgrade
2024-06-14 08:47:47 +02:00
Fabian Dill e9ad7cb797
WebHost: fix option doc indent (#3513)
* WebHost: fix option doc indent

* Update macros.html
2024-06-13 17:37:52 -04:00
NewSoupVi 533395d336
WebHost: Fix Named Range displays on Player Options page (#3521)
* Player Options: Fix Named Range displays

* Also add validation to the NamedRange class itself

* Don't break Stardew

* Comment

* Do replace first so title works correctly

* Bring change to Weighted Options as well
2024-06-13 17:29:39 -04:00
NewSoupVi 2ae51364d9
WebHost: Fix default values that are 2 or more words in Weighted Options (#3519)
* WeightedOptions: Fix default values that are 2 or more words

* So much simpler
2024-06-13 12:24:56 -04:00
NewSoupVi f6e3113af6
WebHost: Fix "Add" button for custom option values causing a weird redirect (#3518)
* WebHost: Fix "Add" button for Progression Balancing causing a weird redirect

This "add" button is part of a form, which causes it to submit the form, because the default type for a button is "submit".

This PR changes the type of the button to "button", which causes it to not submit the form and just execute its normal effect.

(An alternative would be `event.preventDefault()` but that seems less clean to me, but also I'm not a HTML/JS dev)

* There's also multiple.
2024-06-13 04:39:16 -04:00
JoshuaEagles da34800f43
Fix Incorrect Link Syntax in SA2B Linux Setup (#3524) 2024-06-13 06:53:01 +02:00
black-sliver c108845d1f
CI: more checks in build and rework compression (#3336)
* CI: build: fail fast if setup.py fails on windows

* CI: build: fail for missing uploads, rework compression

Upload-artifact allows setting compression level now.
The change speeds up both upload and extraction.

* CI: match build gz in release

* CI: build: verify worlds all load

* CI: build: generate a game

* Generate: move worlds loaded exception to allow settings to init from worlds

* CI: build: build setup before running tests
2024-06-12 18:55:48 +02:00
black-sliver acf85eb9ab
Speedups: remove dependency on c++ (#2796)
* Speedups: remove dependency on c++

* Speedups: intset: handle malloc failing

* Speedups: intset: fix corner case for int64 on 32bit systems

original idea was to only use bucket->val if int<pointer,
but we always have a union now anyway

* Speedups: add size comment to player_set bucket configuration

* test: more tests for LocationStore.find_item

* test: require _speedups in CI

This kind of tests that the build succeeds.

* test: even more tests for LocationStore.find_item

* Speedups: intset uniform comment style

* Speedups: intset: avoid memory leak when realloc fails

* Speedups: intset: make `gcc -pedantic -std=c99 -fanalyzer` without warnings

Unnamed unions are not in C99, this got fixed.
The overhead of setting count=0 is minimal or optimized-out and silences -fanalizer (see comment).

* Speedups: don't leak memory in case of exception

* Speedups: intset: validate alloc and free

This won't happen in our cython, but it's still a good addition.

* CI: add test framework for C/C++ code

* CI: ctest: fix cwd

* Speedups: intset: ignore msvc warning

* Tests: intset: revert attempt at no-asan

We solve this with env vars in ctest now, and this fails for msvc.

* Test: cpp: docs: fix typo

* Test: cpp: docs: fix another typo

* Test: intset: proper bucket count for Negative test

INTxx_MIN % 1 would not produce a negative number, so the test was flawed.
2024-06-12 18:54:59 +02:00
Fabian Dill 2daccded36
Core: don't lock progression (#3501) 2024-06-12 15:35:51 +02:00
Fabian Dill 3b9b9353b7
WebHost: delete old docs files (#3503) 2024-06-12 15:34:46 +02:00
Silvris b9e454ab4e
TS: add indirect connections (#3490) 2024-06-12 03:23:46 +02:00
Natalie Weizenbaum 7299891bdf
Allow worlds to add options to prebuilt groups (#3509)
Previously, this crashed because `typing.NamedTuple` fields such as
`group.name` aren't assignable. Now it will only fail for group names
that are actually incorrectly cased, and will fail with a better error
message.
2024-06-12 03:22:14 +02:00
Fabian Dill e755f1a0b5
SC2: don't close all SC2 instances when one quits (#3507) 2024-06-12 02:14:30 +02:00
Louis M 87d24eb38a
Aquaria: Add entrance rule and fix start_inventory_from_pool (#3473) 2024-06-11 17:59:46 -05:00
Justus Lind 54531c6eba
Muse Dash: Remove regions for a decent speed gain in generating worlds (#3435)
* Remove Muse Dash Regions.

* Update comments.
2024-06-11 03:11:19 +02:00
Zach Parks ccfffa1147
CODEOWNERS: Replace @ThePhar with @qwint as Hollow Knight maintainer. (#3508) 2024-06-10 18:55:02 -05:00
1162 changed files with 140562 additions and 43157 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
worlds/blasphemous/region_data.py linguist-generated=true
worlds/yachtdice/YachtWeights.py linguist-generated=true

View File

@ -1,8 +1,20 @@
{
"include": [
"type_check.py",
"../BizHawkClient.py",
"../Patch.py",
"../test/general/test_groups.py",
"../test/general/test_helpers.py",
"../test/general/test_memory.py",
"../test/general/test_names.py",
"../test/multiworld/__init__.py",
"../test/multiworld/test_multiworlds.py",
"../test/netutils/__init__.py",
"../test/programs/__init__.py",
"../test/programs/test_multi_server.py",
"../test/utils/__init__.py",
"../test/webhost/test_descriptions.py",
"../worlds/AutoSNIClient.py",
"../Patch.py"
"type_check.py"
],
"exclude": [
@ -16,7 +28,7 @@
"reportMissingImports": true,
"reportMissingTypeStubs": true,
"pythonVersion": "3.8",
"pythonVersion": "3.10",
"pythonPlatform": "Windows",
"executionEnvironments": [

View File

@ -53,7 +53,7 @@ jobs:
- uses: actions/setup-python@v5
if: env.diff != ''
with:
python-version: 3.8
python-version: '3.10'
- name: "Install dependencies"
if: env.diff != ''

View File

@ -24,22 +24,28 @@ env:
jobs:
# build-release-macos: # LF volunteer
build-win-py38: # RCs will still be built and signed by hand
build-win: # RCs will still be built and signed by hand
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Install python
uses: actions/setup-python@v5
with:
python-version: '3.8'
python-version: '~3.12.7'
check-latest: true
- name: Download run-time dependencies
run: |
Invoke-WebRequest -Uri https://github.com/Ijwu/Enemizer/releases/download/${Env:ENEMIZER_VERSION}/win-x64.zip -OutFile enemizer.zip
Expand-Archive -Path enemizer.zip -DestinationPath EnemizerCLI -Force
choco install innosetup --version=6.2.2 --allow-downgrade
- name: Build
run: |
python -m pip install --upgrade pip
python setup.py build_exe --yes
if ( $? -eq $false ) {
Write-Error "setup.py failed!"
exit 1
}
$NAME="$(ls build | Select-String -Pattern 'exe')".Split('.',2)[1]
$ZIP_NAME="Archipelago_$NAME.7z"
echo "$NAME -> $ZIP_NAME"
@ -49,12 +55,6 @@ jobs:
Rename-Item "exe.$NAME" Archipelago
7z a -mx=9 -mhe=on -ms "../dist/$ZIP_NAME" Archipelago
Rename-Item Archipelago "exe.$NAME" # inno_setup.iss expects the original name
- name: Store 7z
uses: actions/upload-artifact@v4
with:
name: ${{ env.ZIP_NAME }}
path: dist/${{ env.ZIP_NAME }}
retention-days: 7 # keep for 7 days, should be enough
- name: Build Setup
run: |
& "${env:ProgramFiles(x86)}\Inno Setup 6\iscc.exe" inno_setup.iss /DNO_SIGNTOOL
@ -65,11 +65,38 @@ jobs:
$contents = Get-ChildItem -Path setups/*.exe -Force -Recurse
$SETUP_NAME=$contents[0].Name
echo "SETUP_NAME=$SETUP_NAME" >> $Env:GITHUB_ENV
- name: Check build loads expected worlds
shell: bash
run: |
cd build/exe*
mv Players/Templates/meta.yaml .
ls -1 Players/Templates | sort > setup-player-templates.txt
rm -R Players/Templates
timeout 30 ./ArchipelagoLauncher "Generate Template Options" || true
ls -1 Players/Templates | sort > generated-player-templates.txt
cmp setup-player-templates.txt generated-player-templates.txt \
|| diff setup-player-templates.txt generated-player-templates.txt
mv meta.yaml Players/Templates/
- name: Test Generate
shell: bash
run: |
cd build/exe*
cp Players/Templates/Clique.yaml Players/
timeout 30 ./ArchipelagoGenerate
- name: Store 7z
uses: actions/upload-artifact@v4
with:
name: ${{ env.ZIP_NAME }}
path: dist/${{ env.ZIP_NAME }}
compression-level: 0 # .7z is incompressible by zip
if-no-files-found: error
retention-days: 7 # keep for 7 days, should be enough
- name: Store Setup
uses: actions/upload-artifact@v4
with:
name: ${{ env.SETUP_NAME }}
path: setups/${{ env.SETUP_NAME }}
if-no-files-found: error
retention-days: 7 # keep for 7 days, should be enough
build-ubuntu2004:
@ -85,10 +112,11 @@ jobs:
- name: Get a recent python
uses: actions/setup-python@v5
with:
python-version: '3.11'
python-version: '~3.12.7'
check-latest: true
- name: Install build-time dependencies
run: |
echo "PYTHON=python3.11" >> $GITHUB_ENV
echo "PYTHON=python3.12" >> $GITHUB_ENV
wget -nv https://github.com/AppImage/AppImageKit/releases/download/$APPIMAGETOOL_VERSION/appimagetool-x86_64.AppImage
chmod a+rx appimagetool-x86_64.AppImage
./appimagetool-x86_64.AppImage --appimage-extract
@ -110,7 +138,7 @@ jobs:
echo -e "setup.py dist output:\n `ls dist`"
cd dist && export APPIMAGE_NAME="`ls *.AppImage`" && cd ..
export TAR_NAME="${APPIMAGE_NAME%.AppImage}.tar.gz"
(cd build && DIR_NAME="`ls | grep exe`" && mv "$DIR_NAME" Archipelago && tar -czvf ../dist/$TAR_NAME Archipelago && mv Archipelago "$DIR_NAME")
(cd build && DIR_NAME="`ls | grep exe`" && mv "$DIR_NAME" Archipelago && tar -cv Archipelago | gzip -8 > ../dist/$TAR_NAME && mv Archipelago "$DIR_NAME")
echo "APPIMAGE_NAME=$APPIMAGE_NAME" >> $GITHUB_ENV
echo "TAR_NAME=$TAR_NAME" >> $GITHUB_ENV
# - copy code above to release.yml -
@ -118,15 +146,36 @@ jobs:
run: |
source venv/bin/activate
python setup.py build_exe --yes
- name: Check build loads expected worlds
shell: bash
run: |
cd build/exe*
mv Players/Templates/meta.yaml .
ls -1 Players/Templates | sort > setup-player-templates.txt
rm -R Players/Templates
timeout 30 ./ArchipelagoLauncher "Generate Template Options" || true
ls -1 Players/Templates | sort > generated-player-templates.txt
cmp setup-player-templates.txt generated-player-templates.txt \
|| diff setup-player-templates.txt generated-player-templates.txt
mv meta.yaml Players/Templates/
- name: Test Generate
shell: bash
run: |
cd build/exe*
cp Players/Templates/Clique.yaml Players/
timeout 30 ./ArchipelagoGenerate
- name: Store AppImage
uses: actions/upload-artifact@v4
with:
name: ${{ env.APPIMAGE_NAME }}
path: dist/${{ env.APPIMAGE_NAME }}
if-no-files-found: error
retention-days: 7
- name: Store .tar.gz
uses: actions/upload-artifact@v4
with:
name: ${{ env.TAR_NAME }}
path: dist/${{ env.TAR_NAME }}
compression-level: 0 # .gz is incompressible by zip
if-no-files-found: error
retention-days: 7

View File

@ -47,7 +47,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@ -58,7 +58,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v3
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@ -72,4 +72,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3

54
.github/workflows/ctest.yml vendored Normal file
View File

@ -0,0 +1,54 @@
# Run CMake / CTest C++ unit tests
name: ctest
on:
push:
paths:
- '**.cc?'
- '**.cpp'
- '**.cxx'
- '**.hh?'
- '**.hpp'
- '**.hxx'
- '**.CMakeLists'
- '.github/workflows/ctest.yml'
pull_request:
paths:
- '**.cc?'
- '**.cpp'
- '**.cxx'
- '**.hh?'
- '**.hpp'
- '**.hxx'
- '**.CMakeLists'
- '.github/workflows/ctest.yml'
jobs:
ctest:
runs-on: ${{ matrix.os }}
name: Test C++ ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
if: startsWith(matrix.os,'windows')
- uses: Bacondish2023/setup-googletest@v1
with:
build-type: 'Release'
- name: Build tests
run: |
cd test/cpp
mkdir build
cmake -S . -B build/ -DCMAKE_BUILD_TYPE=Release
cmake --build build/ --config Release
ls
- name: Run tests
run: |
cd test/cpp
ctest --test-dir build/ -C Release --output-on-failure

View File

@ -44,10 +44,11 @@ jobs:
- name: Get a recent python
uses: actions/setup-python@v5
with:
python-version: '3.11'
python-version: '~3.12.7'
check-latest: true
- name: Install build-time dependencies
run: |
echo "PYTHON=python3.11" >> $GITHUB_ENV
echo "PYTHON=python3.12" >> $GITHUB_ENV
wget -nv https://github.com/AppImage/AppImageKit/releases/download/$APPIMAGETOOL_VERSION/appimagetool-x86_64.AppImage
chmod a+rx appimagetool-x86_64.AppImage
./appimagetool-x86_64.AppImage --appimage-extract
@ -69,7 +70,7 @@ jobs:
echo -e "setup.py dist output:\n `ls dist`"
cd dist && export APPIMAGE_NAME="`ls *.AppImage`" && cd ..
export TAR_NAME="${APPIMAGE_NAME%.AppImage}.tar.gz"
(cd build && DIR_NAME="`ls | grep exe`" && mv "$DIR_NAME" Archipelago && tar -czvf ../dist/$TAR_NAME Archipelago && mv Archipelago "$DIR_NAME")
(cd build && DIR_NAME="`ls | grep exe`" && mv "$DIR_NAME" Archipelago && tar -cv Archipelago | gzip -8 > ../dist/$TAR_NAME && mv Archipelago "$DIR_NAME")
echo "APPIMAGE_NAME=$APPIMAGE_NAME" >> $GITHUB_ENV
echo "TAR_NAME=$TAR_NAME" >> $GITHUB_ENV
# - code above copied from build.yml -

View File

@ -40,10 +40,10 @@ jobs:
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x ./llvm.sh
sudo ./llvm.sh 17
sudo ./llvm.sh 19
- name: Install scan-build command
run: |
sudo apt install clang-tools-17
sudo apt install clang-tools-19
- name: Get a recent python
uses: actions/setup-python@v5
with:
@ -56,7 +56,7 @@ jobs:
- name: scan-build
run: |
source venv/bin/activate
scan-build-17 --status-bugs -o scan-build-reports -disable-checker deadcode.DeadStores python setup.py build -y
scan-build-19 --status-bugs -o scan-build-reports -disable-checker deadcode.DeadStores python setup.py build -y
- name: Store report
if: failure()
uses: actions/upload-artifact@v4

View File

@ -26,7 +26,7 @@ jobs:
- name: "Install dependencies"
run: |
python -m pip install --upgrade pip pyright==1.1.358
python -m pip install --upgrade pip pyright==1.1.392.post0
python ModuleUpdate.py --append "WebHostLib/requirements.txt" --force --yes
- name: "pyright: strict check on specific files"

View File

@ -33,16 +33,15 @@ jobs:
matrix:
os: [ubuntu-latest]
python:
- {version: '3.8'}
- {version: '3.9'}
- {version: '3.10'}
- {version: '3.11'}
- {version: '3.12'}
include:
- python: {version: '3.8'} # win7 compat
- python: {version: '3.10'} # old compat
os: windows-latest
- python: {version: '3.11'} # current
- python: {version: '3.12'} # current
os: windows-latest
- python: {version: '3.11'} # current
- python: {version: '3.12'} # current
os: macos-latest
steps:
@ -70,7 +69,7 @@ jobs:
os:
- ubuntu-latest
python:
- {version: '3.11'} # current
- {version: '3.12'} # current
steps:
- uses: actions/checkout@v4
@ -88,4 +87,4 @@ jobs:
run: |
source venv/bin/activate
export PYTHONPATH=$(pwd)
python test/hosting/__main__.py
timeout 600 python test/hosting/__main__.py

3
.gitignore vendored
View File

@ -150,7 +150,7 @@ venv/
ENV/
env.bak/
venv.bak/
.code-workspace
*.code-workspace
shell.nix
# Spyder project settings
@ -178,6 +178,7 @@ dmypy.json
cython_debug/
# Cython intermediates
_speedups.c
_speedups.cpp
_speedups.html

View File

@ -112,7 +112,7 @@ class AdventureContext(CommonContext):
if ': !' not in msg:
self._set_message(msg, SYSTEM_MESSAGE_ID)
elif cmd == "ReceivedItems":
msg = f"Received {', '.join([self.item_names.lookup_in_slot(item.item) for item in args['items']])}"
msg = f"Received {', '.join([self.item_names.lookup_in_game(item.item) for item in args['items']])}"
self._set_message(msg, SYSTEM_MESSAGE_ID)
elif cmd == "Retrieved":
if f"adventure_{self.auth}_freeincarnates_used" in args["keys"]:

View File

@ -1,37 +1,38 @@
from __future__ import annotations
import copy
import itertools
import collections
import functools
import logging
import random
import secrets
import typing # this can go away when Python 3.8 support is dropped
from argparse import Namespace
from collections import Counter, deque
from collections.abc import Collection, MutableSequence
from enum import IntEnum, IntFlag
from typing import Any, Callable, Dict, Iterable, Iterator, List, Mapping, NamedTuple, Optional, Set, Tuple, \
TypedDict, Union, Type, ClassVar
from typing import (AbstractSet, Any, Callable, ClassVar, Dict, Iterable, Iterator, List, Mapping, NamedTuple,
Optional, Protocol, Set, Tuple, Union, TYPE_CHECKING)
from typing_extensions import NotRequired, TypedDict
import NetUtils
import Options
import Utils
if typing.TYPE_CHECKING:
if TYPE_CHECKING:
from entrance_rando import ERPlacementState
from worlds import AutoWorld
class Group(TypedDict, total=False):
class Group(TypedDict):
name: str
game: str
world: "AutoWorld.World"
players: Set[int]
item_pool: Set[str]
replacement_items: Dict[int, Optional[str]]
local_items: Set[str]
non_local_items: Set[str]
link_replacement: bool
players: AbstractSet[int]
item_pool: NotRequired[Set[str]]
replacement_items: NotRequired[Dict[int, Optional[str]]]
local_items: NotRequired[Set[str]]
non_local_items: NotRequired[Set[str]]
link_replacement: NotRequired[bool]
class ThreadBarrierProxy:
@ -48,6 +49,11 @@ class ThreadBarrierProxy:
"Please use multiworld.per_slot_randoms[player] or randomize ahead of output.")
class HasNameAndPlayer(Protocol):
name: str
player: int
class MultiWorld():
debug_types = False
player_name: Dict[int, str]
@ -63,7 +69,6 @@ class MultiWorld():
state: CollectionState
plando_options: PlandoOptions
accessibility: Dict[int, Options.Accessibility]
early_items: Dict[int, Dict[str, int]]
local_early_items: Dict[int, Dict[str, int]]
local_items: Dict[int, Options.LocalItems]
@ -157,7 +162,7 @@ class MultiWorld():
self.start_inventory_from_pool: Dict[int, Options.StartInventoryPool] = {}
for player in range(1, players + 1):
def set_player_attr(attr, val):
def set_player_attr(attr: str, val) -> None:
self.__dict__.setdefault(attr, {})[player] = val
set_player_attr('plando_items', [])
set_player_attr('plando_texts', {})
@ -166,13 +171,13 @@ class MultiWorld():
set_player_attr('completion_condition', lambda state: True)
self.worlds = {}
self.per_slot_randoms = Utils.DeprecateDict("Using per_slot_randoms is now deprecated. Please use the "
"world's random object instead (usually self.random)")
"world's random object instead (usually self.random)")
self.plando_options = PlandoOptions.none
def get_all_ids(self) -> Tuple[int, ...]:
return self.player_ids + tuple(self.groups)
def add_group(self, name: str, game: str, players: Set[int] = frozenset()) -> Tuple[int, Group]:
def add_group(self, name: str, game: str, players: AbstractSet[int] = frozenset()) -> Tuple[int, Group]:
"""Create a group with name and return the assigned player ID and group.
If a group of this name already exists, the set of players is extended instead of creating a new one."""
from worlds import AutoWorld
@ -188,7 +193,9 @@ class MultiWorld():
self.player_types[new_id] = NetUtils.SlotType.group
world_type = AutoWorld.AutoWorldRegister.world_types[game]
self.worlds[new_id] = world_type.create_group(self, new_id, players)
self.worlds[new_id].collect_item = classmethod(AutoWorld.World.collect_item).__get__(self.worlds[new_id])
self.worlds[new_id].collect_item = AutoWorld.World.collect_item.__get__(self.worlds[new_id])
self.worlds[new_id].collect = AutoWorld.World.collect.__get__(self.worlds[new_id])
self.worlds[new_id].remove = AutoWorld.World.remove.__get__(self.worlds[new_id])
self.player_name[new_id] = name
new_group = self.groups[new_id] = Group(name=name, game=game, players=players,
@ -196,7 +203,7 @@ class MultiWorld():
return new_id, new_group
def get_player_groups(self, player) -> Set[int]:
def get_player_groups(self, player: int) -> Set[int]:
return {group_id for group_id, group in self.groups.items() if player in group["players"]}
def set_seed(self, seed: Optional[int] = None, secure: bool = False, name: Optional[str] = None):
@ -223,7 +230,7 @@ class MultiWorld():
for player in self.player_ids:
world_type = AutoWorld.AutoWorldRegister.world_types[self.game[player]]
self.worlds[player] = world_type(self, player)
options_dataclass: typing.Type[Options.PerGameCommonOptions] = world_type.options_dataclass
options_dataclass: type[Options.PerGameCommonOptions] = world_type.options_dataclass
self.worlds[player].options = options_dataclass(**{option_key: getattr(args, option_key)[player]
for option_key in options_dataclass.type_hints})
@ -259,7 +266,7 @@ class MultiWorld():
"link_replacement": replacement_prio.index(item_link["link_replacement"]),
}
for name, item_link in item_links.items():
for _name, item_link in item_links.items():
current_item_name_groups = AutoWorld.AutoWorldRegister.world_types[item_link["game"]].item_name_groups
pool = set()
local_items = set()
@ -288,6 +295,88 @@ class MultiWorld():
group["non_local_items"] = item_link["non_local_items"]
group["link_replacement"] = replacement_prio[item_link["link_replacement"]]
def link_items(self) -> None:
"""Called to link together items in the itempool related to the registered item link groups."""
from worlds import AutoWorld
for group_id, group in self.groups.items():
def find_common_pool(players: Set[int], shared_pool: Set[str]) -> Tuple[
Optional[Dict[int, Dict[str, int]]], Optional[Dict[str, int]]
]:
classifications: Dict[str, int] = collections.defaultdict(int)
counters = {player: {name: 0 for name in shared_pool} for player in players}
for item in self.itempool:
if item.player in counters and item.name in shared_pool:
counters[item.player][item.name] += 1
classifications[item.name] |= item.classification
for player in players.copy():
if all([counters[player][item] == 0 for item in shared_pool]):
players.remove(player)
del (counters[player])
if not players:
return None, None
for item in shared_pool:
count = min(counters[player][item] for player in players)
if count:
for player in players:
counters[player][item] = count
else:
for player in players:
del (counters[player][item])
return counters, classifications
common_item_count, classifications = find_common_pool(group["players"], group["item_pool"])
if not common_item_count:
continue
new_itempool: List[Item] = []
for item_name, item_count in next(iter(common_item_count.values())).items():
for _ in range(item_count):
new_item = group["world"].create_item(item_name)
# mangle together all original classification bits
new_item.classification |= classifications[item_name]
new_itempool.append(new_item)
region = Region(group["world"].origin_region_name, group_id, self, "ItemLink")
self.regions.append(region)
locations = region.locations
# ensure that progression items are linked first, then non-progression
self.itempool.sort(key=lambda item: item.advancement)
for item in self.itempool:
count = common_item_count.get(item.player, {}).get(item.name, 0)
if count:
loc = Location(group_id, f"Item Link: {item.name} -> {self.player_name[item.player]} {count}",
None, region)
loc.access_rule = lambda state, item_name = item.name, group_id_ = group_id, count_ = count: \
state.has(item_name, group_id_, count_)
locations.append(loc)
loc.place_locked_item(item)
common_item_count[item.player][item.name] -= 1
else:
new_itempool.append(item)
itemcount = len(self.itempool)
self.itempool = new_itempool
while itemcount > len(self.itempool):
items_to_add = []
for player in group["players"]:
if group["link_replacement"]:
item_player = group_id
else:
item_player = player
if group["replacement_items"][player]:
items_to_add.append(AutoWorld.call_single(self, "create_item", item_player,
group["replacement_items"][player]))
else:
items_to_add.append(AutoWorld.call_single(self, "create_filler", item_player))
self.random.shuffle(items_to_add)
self.itempool.extend(items_to_add[:itemcount - len(self.itempool)])
def secure(self):
self.random = ThreadBarrierProxy(secrets.SystemRandom())
self.is_race = True
@ -309,7 +398,7 @@ class MultiWorld():
return tuple(world for player, world in self.worlds.items() if
player not in self.groups and self.game[player] == game_name)
def get_name_string_for_object(self, obj) -> str:
def get_name_string_for_object(self, obj: HasNameAndPlayer) -> str:
return obj.name if self.players == 1 else f'{obj.name} ({self.get_player_name(obj.player)})'
def get_player_name(self, player: int) -> str:
@ -338,12 +427,12 @@ class MultiWorld():
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) -> CollectionState:
def get_all_state(self, use_cache: bool, allow_partial_entrances: bool = False) -> CollectionState:
cached = getattr(self, "_all_state", None)
if use_cache and cached:
return cached.copy()
ret = CollectionState(self)
ret = CollectionState(self, allow_partial_entrances)
for item in self.itempool:
self.worlds[item.player].collect(ret, item)
@ -351,7 +440,7 @@ class MultiWorld():
subworld = self.worlds[player]
for item in subworld.get_pre_fill_items():
subworld.collect(ret, item)
ret.sweep_for_events()
ret.sweep_for_advancements()
if use_cache:
self._all_state = ret
@ -360,7 +449,7 @@ class MultiWorld():
def get_items(self) -> List[Item]:
return [loc.item for loc in self.get_filled_locations()] + self.itempool
def find_item_locations(self, item, player: int, resolve_group_locations: bool = False) -> List[Location]:
def find_item_locations(self, item: str, player: int, resolve_group_locations: bool = False) -> List[Location]:
if resolve_group_locations:
player_groups = self.get_player_groups(player)
return [location for location in self.get_locations() if
@ -369,7 +458,7 @@ class MultiWorld():
return [location for location in self.get_locations() if
location.item and location.item.name == item and location.item.player == player]
def find_item(self, item, player: int) -> Location:
def find_item(self, item: str, player: int) -> Location:
return next(location for location in self.get_locations() if
location.item and location.item.name == item and location.item.player == player)
@ -462,9 +551,9 @@ class MultiWorld():
return True
state = starting_state.copy()
else:
if self.has_beaten_game(self.state):
return True
state = CollectionState(self)
if self.has_beaten_game(state):
return True
prog_locations = {location for location in self.get_locations() if location.item
and location.item.advancement and location not in state.locations_checked}
@ -516,6 +605,49 @@ class MultiWorld():
state.collect(location.item, True, location)
locations -= sphere
def get_sendable_spheres(self) -> Iterator[Set[Location]]:
"""
yields a set of multiserver sendable locations (location.item.code: int) for each logical sphere
If there are unreachable locations, the last sphere of reachable locations is followed by an empty set,
and then a set of all of the unreachable locations.
"""
state = CollectionState(self)
locations: Set[Location] = set()
events: Set[Location] = set()
for location in self.get_filled_locations():
if type(location.item.code) is int:
locations.add(location)
else:
events.add(location)
while locations:
sphere: Set[Location] = set()
# cull events out
done_events: Set[Union[Location, None]] = {None}
while done_events:
done_events = set()
for event in events:
if event.can_reach(state):
state.collect(event.item, True, event)
done_events.add(event)
events -= done_events
for location in locations:
if location.can_reach(state):
sphere.add(location)
yield sphere
if not sphere:
if locations:
yield locations # unreachable locations
break
for location in sphere:
state.collect(location.item, True, location)
locations -= sphere
def fulfills_accessibility(self, state: Optional[CollectionState] = None):
"""Check if accessibility rules are fulfilled with current or supplied state."""
if not state:
@ -523,26 +655,21 @@ class MultiWorld():
players: Dict[str, Set[int]] = {
"minimal": set(),
"items": set(),
"locations": set()
"full": set()
}
for player, access in self.accessibility.items():
players[access.current_key].add(player)
for player, world in self.worlds.items():
players[world.options.accessibility.current_key].add(player)
beatable_fulfilled = False
def location_condition(location: Location):
def location_condition(location: Location) -> bool:
"""Determine if this location has to be accessible, location is already filtered by location_relevant"""
if location.player in players["locations"] or (location.item and location.item.player not in
players["minimal"]):
return True
return False
return location.player in players["full"] or \
(location.item and location.item.player not in players["minimal"])
def location_relevant(location: Location):
def location_relevant(location: Location) -> bool:
"""Determine if this location is relevant to sweep."""
if location.progress_type != LocationProgressType.EXCLUDED \
and (location.player in players["locations"] or location.advancement):
return True
return False
return location.player in players["full"] or location.advancement
def all_done() -> bool:
"""Check if all access rules are fulfilled"""
@ -587,22 +714,24 @@ class CollectionState():
multiworld: MultiWorld
reachable_regions: Dict[int, Set[Region]]
blocked_connections: Dict[int, Set[Entrance]]
events: Set[Location]
advancements: Set[Location]
path: Dict[Union[Region, Entrance], PathValue]
locations_checked: Set[Location]
stale: Dict[int, bool]
allow_partial_entrances: bool
additional_init_functions: List[Callable[[CollectionState, MultiWorld], None]] = []
additional_copy_functions: List[Callable[[CollectionState, CollectionState], CollectionState]] = []
def __init__(self, parent: MultiWorld):
def __init__(self, parent: MultiWorld, allow_partial_entrances: bool = False):
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()}
self.blocked_connections = {player: set() for player in parent.get_all_ids()}
self.events = set()
self.advancements = set()
self.path = {}
self.locations_checked = set()
self.stale = {player: True for player in parent.get_all_ids()}
self.allow_partial_entrances = allow_partial_entrances
for function in self.additional_init_functions:
function(self, parent)
for items in parent.precollected_items.values():
@ -611,17 +740,25 @@ class CollectionState():
def update_reachable_regions(self, player: int):
self.stale[player] = False
world: AutoWorld.World = self.multiworld.worlds[player]
reachable_regions = self.reachable_regions[player]
blocked_connections = self.blocked_connections[player]
queue = deque(self.blocked_connections[player])
start = self.multiworld.get_region("Menu", player)
start: Region = world.get_region(world.origin_region_name)
# init on first call - this can't be done on construction since the regions don't exist yet
if start not in reachable_regions:
reachable_regions.add(start)
blocked_connections.update(start.exits)
self.blocked_connections[player].update(start.exits)
queue.extend(start.exits)
if world.explicit_indirect_conditions:
self._update_reachable_regions_explicit_indirect_conditions(player, queue)
else:
self._update_reachable_regions_auto_indirect_conditions(player, queue)
def _update_reachable_regions_explicit_indirect_conditions(self, player: int, queue: deque):
reachable_regions = self.reachable_regions[player]
blocked_connections = self.blocked_connections[player]
# run BFS on all connections, and keep track of those blocked by missing items
while queue:
connection = queue.popleft()
@ -629,7 +766,9 @@ class CollectionState():
if new_region in reachable_regions:
blocked_connections.remove(connection)
elif connection.can_reach(self):
assert new_region, f"tried to search through an Entrance \"{connection}\" with no Region"
if self.allow_partial_entrances and not new_region:
continue
assert new_region, f"tried to search through an Entrance \"{connection}\" with no connected Region"
reachable_regions.add(new_region)
blocked_connections.remove(connection)
blocked_connections.update(new_region.exits)
@ -641,16 +780,42 @@ class CollectionState():
if new_entrance in blocked_connections and new_entrance not in queue:
queue.append(new_entrance)
def _update_reachable_regions_auto_indirect_conditions(self, player: int, queue: deque):
reachable_regions = self.reachable_regions[player]
blocked_connections = self.blocked_connections[player]
new_connection: bool = True
# run BFS on all connections, and keep track of those blocked by missing items
while new_connection:
new_connection = False
while queue:
connection = queue.popleft()
new_region = connection.connected_region
if new_region in reachable_regions:
blocked_connections.remove(connection)
elif connection.can_reach(self):
if self.allow_partial_entrances and not new_region:
continue
assert new_region, f"tried to search through an Entrance \"{connection}\" with no connected Region"
reachable_regions.add(new_region)
blocked_connections.remove(connection)
blocked_connections.update(new_region.exits)
queue.extend(new_region.exits)
self.path[new_region] = (new_region.name, self.path.get(connection, None))
new_connection = True
# sweep for indirect connections, mostly Entrance.can_reach(unrelated_Region)
queue.extend(blocked_connections)
def copy(self) -> CollectionState:
ret = CollectionState(self.multiworld)
ret.prog_items = copy.deepcopy(self.prog_items)
ret.reachable_regions = {player: copy.copy(self.reachable_regions[player]) for player in
self.reachable_regions}
ret.blocked_connections = {player: copy.copy(self.blocked_connections[player]) for player in
self.blocked_connections}
ret.events = copy.copy(self.events)
ret.path = copy.copy(self.path)
ret.locations_checked = copy.copy(self.locations_checked)
ret.prog_items = {player: counter.copy() for player, counter in self.prog_items.items()}
ret.reachable_regions = {player: region_set.copy() for player, region_set in
self.reachable_regions.items()}
ret.blocked_connections = {player: entrance_set.copy() for player, entrance_set in
self.blocked_connections.items()}
ret.advancements = self.advancements.copy()
ret.path = self.path.copy()
ret.locations_checked = self.locations_checked.copy()
ret.allow_partial_entrances = self.allow_partial_entrances
for function in self.additional_copy_functions:
ret = function(self, ret)
return ret
@ -680,20 +845,25 @@ class CollectionState():
def can_reach_region(self, spot: str, player: int) -> bool:
return self.multiworld.get_region(spot, player).can_reach(self)
def sweep_for_events(self, key_only: bool = False, locations: Optional[Iterable[Location]] = None) -> None:
def sweep_for_events(self, locations: Optional[Iterable[Location]] = None) -> None:
Utils.deprecate("sweep_for_events has been renamed to sweep_for_advancements. The functionality is the same. "
"Please switch over to sweep_for_advancements.")
return self.sweep_for_advancements(locations)
def sweep_for_advancements(self, locations: Optional[Iterable[Location]] = None) -> None:
if locations is None:
locations = self.multiworld.get_filled_locations()
reachable_events = True
# since the loop has a good chance to run more than once, only filter the events once
locations = {location for location in locations if location.advancement and location not in self.events and
not key_only or getattr(location.item, "locked_dungeon_item", False)}
while reachable_events:
reachable_events = {location for location in locations if location.can_reach(self)}
locations -= reachable_events
for event in reachable_events:
self.events.add(event)
assert isinstance(event.item, Item), "tried to collect Event with no Item"
self.collect(event.item, True, event)
reachable_advancements = True
# since the loop has a good chance to run more than once, only filter the advancements once
locations = {location for location in locations if location.advancement and location not in self.advancements}
while reachable_advancements:
reachable_advancements = {location for location in locations if location.can_reach(self)}
locations -= reachable_advancements
for advancement in reachable_advancements:
self.advancements.add(advancement)
assert isinstance(advancement.item, Item), "tried to collect Event with no Item"
self.collect(advancement.item, True, advancement)
# item name related
def has(self, item: str, player: int, count: int = 1) -> bool:
@ -727,7 +897,7 @@ class CollectionState():
if found >= count:
return True
return False
def has_from_list_unique(self, items: Iterable[str], player: int, count: int) -> bool:
"""Returns True if the state contains at least `count` items matching any of the item names from a list.
Ignores duplicates of the same item."""
@ -742,7 +912,7 @@ class CollectionState():
def count_from_list(self, items: Iterable[str], player: int) -> int:
"""Returns the cumulative count of items from a list present in state."""
return sum(self.prog_items[player][item_name] for item_name in items)
def count_from_list_unique(self, items: Iterable[str], player: int) -> int:
"""Returns the cumulative count of items from a list present in state. Ignores duplicates of the same item."""
return sum(self.prog_items[player][item_name] > 0 for item_name in items)
@ -788,20 +958,16 @@ class CollectionState():
)
# Item related
def collect(self, item: Item, event: bool = False, location: Optional[Location] = None) -> bool:
def collect(self, item: Item, prevent_sweep: bool = False, location: Optional[Location] = None) -> bool:
if location:
self.locations_checked.add(location)
changed = self.multiworld.worlds[item.player].collect(self, item)
if not changed and event:
self.prog_items[item.player][item.name] += 1
changed = True
self.stale[item.player] = True
if changed and not event:
self.sweep_for_events()
if changed and not prevent_sweep:
self.sweep_for_advancements()
return changed
@ -814,6 +980,11 @@ class CollectionState():
self.stale[item.player] = True
class EntranceType(IntEnum):
ONE_WAY = 1
TWO_WAY = 2
class Entrance:
access_rule: Callable[[CollectionState], bool] = staticmethod(lambda state: True)
hide_path: bool = False
@ -821,18 +992,24 @@ class Entrance:
name: str
parent_region: Optional[Region]
connected_region: Optional[Region] = None
randomization_group: int
randomization_type: EntranceType
# LttP specific, TODO: should make a LttPEntrance
addresses = None
target = None
def __init__(self, player: int, name: str = '', parent: Region = None):
def __init__(self, player: int, name: str = "", parent: Optional[Region] = None,
randomization_group: int = 0, randomization_type: EntranceType = EntranceType.ONE_WAY) -> None:
self.name = name
self.parent_region = parent
self.player = player
self.randomization_group = randomization_group
self.randomization_type = randomization_type
def can_reach(self, state: CollectionState) -> bool:
assert self.parent_region, f"called can_reach on an Entrance \"{self}\" with no parent_region"
if self.parent_region.can_reach(state) and self.access_rule(state):
if not self.hide_path and not self in state.path:
if not self.hide_path and self not in state.path:
state.path[self] = (self.name, state.path.get(self.parent_region, (self.parent_region.name, None)))
return True
@ -844,10 +1021,33 @@ class Entrance:
self.addresses = addresses
region.entrances.append(self)
def __repr__(self):
return self.__str__()
def is_valid_source_transition(self, er_state: "ERPlacementState") -> bool:
"""
Determines whether this is a valid source transition, that is, whether the entrance
randomizer is allowed to pair it to place any other regions. By default, this is the
same as a reachability check, but can be modified by Entrance implementations to add
other restrictions based on the placement state.
def __str__(self):
:param er_state: The current (partial) state of the ongoing entrance randomization
"""
return self.can_reach(er_state.collection_state)
def can_connect_to(self, other: Entrance, dead_end: bool, er_state: "ERPlacementState") -> bool:
"""
Determines whether a given Entrance is a valid target transition, that is, whether
the entrance randomizer is allowed to pair this Entrance to that Entrance. By default,
only allows connection between entrances of the same type (one ways only go to one ways,
two ways always go to two ways) and prevents connecting an exit to itself in coupled mode.
:param other: The proposed Entrance to connect to
:param dead_end: Whether the other entrance considered a dead end by Entrance randomization
:param er_state: The current (partial) state of the ongoing entrance randomization
"""
# the implementation of coupled causes issues for self-loops since the reverse entrance will be the
# same as the forward entrance. In uncoupled they are ok.
return self.randomization_type == other.randomization_type and (not er_state.coupled or self.name != other.name)
def __repr__(self):
multiworld = self.parent_region.multiworld if self.parent_region else None
return multiworld.get_name_string_for_object(self) if multiworld else f'{self.name} (Player {self.player})'
@ -860,7 +1060,7 @@ class Region:
entrances: List[Entrance]
exits: List[Entrance]
locations: List[Location]
entrance_type: ClassVar[Type[Entrance]] = Entrance
entrance_type: ClassVar[type[Entrance]] = Entrance
class Register(MutableSequence):
region_manager: MultiWorld.RegionManager
@ -960,7 +1160,7 @@ class Region:
return entrance.parent_region.get_connecting_entrance(is_main_entrance)
def add_locations(self, locations: Dict[str, Optional[int]],
location_type: Optional[Type[Location]] = None) -> None:
location_type: Optional[type[Location]] = None) -> None:
"""
Adds locations to the Region object, where location_type is your Location class and locations is a dict of
location names to address.
@ -973,7 +1173,7 @@ class Region:
self.locations.append(location_type(self.player, location, address, self))
def connect(self, connecting_region: Region, name: Optional[str] = None,
rule: Optional[Callable[[CollectionState], bool]] = None) -> entrance_type:
rule: Optional[Callable[[CollectionState], bool]] = None) -> Entrance:
"""
Connects this Region to another Region, placing the provided rule on the connection.
@ -996,8 +1196,18 @@ class Region:
self.exits.append(exit_)
return exit_
def create_er_target(self, name: str) -> Entrance:
"""
Creates and returns an Entrance object as an entrance to this region
:param name: name of the Entrance being created
"""
entrance = self.entrance_type(self.player, name)
entrance.connect(self)
return entrance
def add_exits(self, exits: Union[Iterable[str], Dict[str, Optional[str]]],
rules: Dict[str, Callable[[CollectionState], bool]] = None) -> None:
rules: Dict[str, Callable[[CollectionState], bool]] = None) -> List[Entrance]:
"""
Connects current region to regions in exit dictionary. Passed region names must exist first.
@ -1007,15 +1217,16 @@ class Region:
"""
if not isinstance(exits, Dict):
exits = dict.fromkeys(exits)
for connecting_region, name in exits.items():
self.connect(self.multiworld.get_region(connecting_region, self.player),
name,
rules[connecting_region] if rules and connecting_region in rules else None)
return [
self.connect(
self.multiworld.get_region(connecting_region, self.player),
name,
rules[connecting_region] if rules and connecting_region in rules else None,
)
for connecting_region, name in exits.items()
]
def __repr__(self):
return self.__str__()
def __str__(self):
return self.multiworld.get_name_string_for_object(self) if self.multiworld else f'{self.name} (Player {self.player})'
@ -1034,9 +1245,9 @@ class Location:
locked: bool = False
show_in_spoiler: bool = True
progress_type: LocationProgressType = LocationProgressType.DEFAULT
always_allow = staticmethod(lambda state, item: False)
always_allow: Callable[[CollectionState, Item], bool] = staticmethod(lambda state, item: False)
access_rule: Callable[[CollectionState], bool] = staticmethod(lambda state: True)
item_rule = staticmethod(lambda item: True)
item_rule: Callable[[Item], bool] = staticmethod(lambda item: True)
item: Optional[Item] = None
def __init__(self, player: int, name: str = '', address: Optional[int] = None, parent: Optional[Region] = None):
@ -1045,16 +1256,20 @@ class Location:
self.address = address
self.parent_region = parent
def can_fill(self, state: CollectionState, item: Item, check_access=True) -> bool:
return ((self.always_allow(state, item) and item.name not in state.multiworld.worlds[item.player].options.non_local_items)
or ((self.progress_type != LocationProgressType.EXCLUDED or not (item.advancement or item.useful))
and self.item_rule(item)
and (not check_access or self.can_reach(state))))
def can_fill(self, state: CollectionState, item: Item, check_access: bool = True) -> bool:
return ((
self.always_allow(state, item)
and item.name not in state.multiworld.worlds[item.player].options.non_local_items
) or (
(self.progress_type != LocationProgressType.EXCLUDED or not (item.advancement or item.useful))
and self.item_rule(item)
and (not check_access or self.can_reach(state))
))
def can_reach(self, state: CollectionState) -> bool:
# self.access_rule computes faster on average, so placing it first for faster abort
assert self.parent_region, "Can't reach location without region"
return self.access_rule(state) and self.parent_region.can_reach(state)
# Region.can_reach is just a cache lookup, so placing it first for faster abort on average
assert self.parent_region, f"called can_reach on a Location \"{self}\" with no parent_region"
return self.parent_region.can_reach(state) and self.access_rule(state)
def place_locked_item(self, item: Item):
if self.item:
@ -1064,9 +1279,6 @@ class Location:
self.locked = True
def __repr__(self):
return self.__str__()
def __str__(self):
multiworld = self.parent_region.multiworld if self.parent_region and self.parent_region.multiworld else None
return multiworld.get_name_string_for_object(self) if multiworld else f'{self.name} (Player {self.player})'
@ -1088,7 +1300,7 @@ class Location:
@property
def native_item(self) -> bool:
"""Returns True if the item in this location matches game."""
return self.item and self.item.game == self.game
return self.item is not None and self.item.game == self.game
@property
def hint_text(self) -> str:
@ -1096,13 +1308,26 @@ class Location:
class ItemClassification(IntFlag):
filler = 0b0000 # aka trash, as in filler items like ammo, currency etc,
progression = 0b0001 # Item that is logically relevant
useful = 0b0010 # Item that is generally quite useful, but not required for anything logical
trap = 0b0100 # detrimental or entirely useless (nothing) item
skip_balancing = 0b1000 # should technically never occur on its own
# Item that is logically relevant, but progression balancing should not touch.
# Typically currency or other counted items.
filler = 0b0000
""" aka trash, as in filler items like ammo, currency etc """
progression = 0b0001
""" Item that is logically relevant.
Protects this item from being placed on excluded or unreachable locations. """
useful = 0b0010
""" Item that is especially useful.
Protects this item from being placed on excluded or unreachable locations.
When combined with another flag like "progression", it means "an especially useful progression item". """
trap = 0b0100
""" Item that is detrimental in some way. """
skip_balancing = 0b1000
""" should technically never occur on its own
Item that is logically relevant, but progression balancing should not touch.
Typically currency or other counted items. """
progression_skip_balancing = 0b1001 # only progression gets balanced
def as_flag(self) -> int:
@ -1151,6 +1376,14 @@ class Item:
def trap(self) -> bool:
return ItemClassification.trap in self.classification
@property
def filler(self) -> bool:
return not (self.advancement or self.useful or self.trap)
@property
def excludable(self) -> bool:
return not (self.advancement or self.useful)
@property
def flags(self) -> int:
return self.classification.as_flag()
@ -1171,9 +1404,6 @@ class Item:
return hash((self.name, self.player))
def __repr__(self) -> str:
return self.__str__()
def __str__(self) -> str:
if self.location and self.location.parent_region and self.location.parent_region.multiworld:
return self.location.parent_region.multiworld.get_name_string_for_object(self)
return f"{self.name} (Player {self.player})"
@ -1251,9 +1481,9 @@ class Spoiler:
# 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 = {}
restore_later: Dict[Location, Item] = {}
for num, sphere in reversed(tuple(enumerate(collection_spheres))):
to_delete = set()
to_delete: Set[Location] = set()
for location in sphere:
# we remove the item at location and check if game is still beatable
logging.debug('Checking if %s (Player %d) is required to beat the game.', location.item.name,
@ -1271,15 +1501,22 @@ class Spoiler:
sphere -= to_delete
# second phase, sphere 0
removed_precollected = []
for item in (i for i in chain.from_iterable(multiworld.precollected_items.values()) if i.advancement):
logging.debug('Checking if %s (Player %d) is required to beat the game.', item.name, item.player)
multiworld.precollected_items[item.player].remove(item)
multiworld.state.remove(item)
if not multiworld.can_beat_game():
multiworld.push_precollected(item)
else:
removed_precollected.append(item)
removed_precollected: List[Item] = []
for precollected_items in multiworld.precollected_items.values():
# The list of items is mutated by removing one item at a time to determine if each item is required to beat
# the game, and re-adding that item if it was required, so a copy needs to be made before iterating.
for item in precollected_items.copy():
if not item.advancement:
continue
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():
# Add the item back into `precollected_items` and collect it into `multiworld.state`.
multiworld.push_precollected(item)
else:
removed_precollected.append(item)
# we are now down to just the required progress items in collection_spheres. Unfortunately
# the previous pruning stage could potentially have made certain items dependant on others
@ -1291,8 +1528,6 @@ class Spoiler:
state = CollectionState(multiworld)
collection_spheres = []
while required_locations:
state.sweep_for_events(key_only=True)
sphere = set(filter(state.can_reach, required_locations))
for location in sphere:
@ -1354,7 +1589,7 @@ class Spoiler:
# Maybe move the big bomb over to the Event system instead?
if any(exit_path == 'Pyramid Fairy' for path in self.paths.values()
for (_, exit_path) in path):
if multiworld.mode[player] != 'inverted':
if multiworld.worlds[player].options.mode != 'inverted':
self.paths[str(multiworld.get_region('Big Bomb Shop', player))] = \
get_path(state, multiworld.get_region('Big Bomb Shop', player))
else:
@ -1420,15 +1655,15 @@ class Spoiler:
[f" {location}: {item}" for (location, item) in sphere.items()] if isinstance(sphere, dict) else
[f" {item}" for item in sphere])) for (sphere_nr, sphere) in self.playthrough.items()]))
if self.unreachables:
outfile.write('\n\nUnreachable Items:\n\n')
outfile.write('\n\nUnreachable Progression Items:\n\n')
outfile.write(
'\n'.join(['%s: %s' % (unreachable.item, unreachable) for unreachable in self.unreachables]))
if self.paths:
outfile.write('\n\nPaths:\n\n')
path_listings = []
path_listings: List[str] = []
for location, path in sorted(self.paths.items()):
path_lines = []
path_lines: List[str] = []
for region, exit in path:
if exit is not None:
path_lines.append("{} -> {}".format(region, exit))

View File

@ -1,9 +1,10 @@
from __future__ import annotations
import sys
import ModuleUpdate
ModuleUpdate.update()
from worlds._bizhawk.context import launch
if __name__ == "__main__":
launch()
launch(*sys.argv[1:])

View File

@ -23,7 +23,7 @@ if __name__ == "__main__":
from MultiServer import CommandProcessor
from NetUtils import (Endpoint, decode, NetworkItem, encode, JSONtoTextParser, ClientStatus, Permission, NetworkSlot,
RawJSONtoTextParser, add_json_text, add_json_location, add_json_item, JSONTypes)
RawJSONtoTextParser, add_json_text, add_json_location, add_json_item, JSONTypes, HintStatus, SlotType)
from Utils import Version, stream_input, async_start
from worlds import network_data_package, AutoWorldRegister
import os
@ -31,6 +31,7 @@ import ssl
if typing.TYPE_CHECKING:
import kvui
import argparse
logger = logging.getLogger("Client")
@ -45,10 +46,21 @@ def get_ssl_context():
class ClientCommandProcessor(CommandProcessor):
"""
The Command Processor will parse every method of the class that starts with "_cmd_" as a command to be called
when parsing user input, i.e. _cmd_exit will be called when the user sends the command "/exit".
The decorator @mark_raw can be imported from MultiServer and tells the parser to only split on the first
space after the command i.e. "/exit one two three" will be passed in as method("one two three") with mark_raw
and method("one", "two", "three") without.
In addition all docstrings for command methods will be displayed to the user on launch and when using "/help"
"""
def __init__(self, ctx: CommonContext):
self.ctx = ctx
def output(self, text: str):
"""Helper function to abstract logging to the CommonClient UI"""
logger.info(text)
def _cmd_exit(self) -> bool:
@ -61,6 +73,7 @@ class ClientCommandProcessor(CommandProcessor):
if address:
self.ctx.server_address = None
self.ctx.username = None
self.ctx.password = None
elif not self.ctx.server_address:
self.output("Please specify an address.")
return False
@ -163,13 +176,14 @@ class ClientCommandProcessor(CommandProcessor):
async_start(self.ctx.send_msgs([{"cmd": "StatusUpdate", "status": state}]), name="send StatusUpdate")
def default(self, raw: str):
"""The default message parser to be used when parsing any messages that do not match a command"""
raw = self.ctx.on_user_say(raw)
if raw:
async_start(self.ctx.send_msgs([{"cmd": "Say", "text": raw}]), name="send Say")
class CommonContext:
# Should be adjusted as needed in subclasses
# The following attributes are used to Connect and should be adjusted as needed in subclasses
tags: typing.Set[str] = {"AP"}
game: typing.Optional[str] = None
items_handling: typing.Optional[int] = None
@ -225,6 +239,9 @@ class CommonContext:
def lookup_in_slot(self, code: int, slot: typing.Optional[int] = None) -> str:
"""Returns the name for an item/location id in the context of a specific slot or own slot if `slot` is
omitted.
Use of `lookup_in_slot` should not be used when not connected to a server. If looking in own game, set
`ctx.game` and use `lookup_in_game` method instead.
"""
if slot is None:
slot = self.ctx.slot
@ -248,7 +265,7 @@ class CommonContext:
starting_reconnect_delay: int = 5
current_reconnect_delay: int = starting_reconnect_delay
command_processor: typing.Type[CommandProcessor] = ClientCommandProcessor
ui = None
ui: typing.Optional["kvui.GameManager"] = None
ui_task: typing.Optional["asyncio.Task[None]"] = None
input_task: typing.Optional["asyncio.Task[None]"] = None
keep_alive_task: typing.Optional["asyncio.Task[None]"] = None
@ -339,6 +356,8 @@ class CommonContext:
self.item_names = self.NameLookupDict(self, "item")
self.location_names = self.NameLookupDict(self, "location")
self.versions = {}
self.checksums = {}
self.jsontotextparser = JSONtoTextParser(self)
self.rawjsontotextparser = RawJSONtoTextParser(self)
@ -394,6 +413,7 @@ class CommonContext:
await self.server.socket.close()
if self.server_task is not None:
await self.server_task
self.ui.update_hints()
async def send_msgs(self, msgs: typing.List[typing.Any]) -> None:
""" `msgs` JSON serializable """
@ -425,7 +445,10 @@ class CommonContext:
self.auth = await self.console_input()
async def send_connect(self, **kwargs: typing.Any) -> None:
""" send `Connect` packet to log in to server """
"""
Send a `Connect` packet to log in to the server,
additional keyword args can override any value in the connection packet
"""
payload = {
'cmd': 'Connect',
'password': self.password, 'name': self.auth, 'version': Utils.version_tuple,
@ -435,6 +458,14 @@ class CommonContext:
if kwargs:
payload.update(kwargs)
await self.send_msgs([payload])
await self.send_msgs([{"cmd": "Get", "keys": ["_read_race_mode"]}])
async def check_locations(self, locations: typing.Collection[int]) -> set[int]:
"""Send new location checks to the server. Returns the set of actually new locations that were sent."""
locations = set(locations) & self.missing_locations
if locations:
await self.send_msgs([{"cmd": 'LocationChecks', "locations": tuple(locations)}])
return locations
async def console_input(self) -> str:
if self.ui:
@ -455,6 +486,7 @@ class CommonContext:
return False
def slot_concerns_self(self, slot) -> bool:
"""Helper function to abstract player groups, should be used instead of checking slot == self.slot directly."""
if slot == self.slot:
return True
if slot in self.slot_info:
@ -462,6 +494,7 @@ class CommonContext:
return False
def is_echoed_chat(self, print_json_packet: dict) -> bool:
"""Helper function for filtering out messages sent by self."""
return print_json_packet.get("type", "") == "Chat" \
and print_json_packet.get("team", None) == self.team \
and print_json_packet.get("slot", None) == self.slot
@ -493,13 +526,14 @@ class CommonContext:
"""Gets called before sending a Say to the server from the user.
Returned text is sent, or sending is aborted if None is returned."""
return text
def on_ui_command(self, text: str) -> None:
"""Gets called by kivy when the user executes a command starting with `/` or `!`.
The command processor is still called; this is just intended for command echoing."""
self.ui.print_json([{"text": text, "type": "color", "color": "orange"}])
def update_permissions(self, permissions: typing.Dict[str, int]):
"""Internal method to parse and save server permissions from RoomInfo"""
for permission_name, permission_flag in permissions.items():
try:
flag = Permission(permission_flag)
@ -511,6 +545,7 @@ class CommonContext:
async def shutdown(self):
self.server_address = ""
self.username = None
self.password = None
self.cancel_autoreconnect()
if self.server and not self.server.socket.closed:
await self.server.socket.close()
@ -525,7 +560,14 @@ class CommonContext:
await self.ui_task
if self.input_task:
self.input_task.cancel()
# Hints
def update_hint(self, location: int, finding_player: int, status: typing.Optional[HintStatus]) -> None:
msg = {"cmd": "UpdateHint", "location": location, "player": finding_player}
if status is not None:
msg["status"] = status
async_start(self.send_msgs([msg]), name="update_hint")
# DataPackage
async def prepare_data_package(self, relevant_games: typing.Set[str],
remote_date_package_versions: typing.Dict[str, int],
@ -547,26 +589,34 @@ class CommonContext:
needed_updates.add(game)
continue
local_version: int = network_data_package["games"].get(game, {}).get("version", 0)
local_checksum: typing.Optional[str] = network_data_package["games"].get(game, {}).get("checksum")
# no action required if local version is new enough
if (not remote_checksum and (remote_version > local_version or remote_version == 0)) \
or remote_checksum != local_checksum:
cached_game = Utils.load_data_package_for_checksum(game, remote_checksum)
cache_version: int = cached_game.get("version", 0)
cache_checksum: typing.Optional[str] = cached_game.get("checksum")
# download remote version if cache is not new enough
if (not remote_checksum and (remote_version > cache_version or remote_version == 0)) \
or remote_checksum != cache_checksum:
needed_updates.add(game)
cached_version: int = self.versions.get(game, 0)
cached_checksum: typing.Optional[str] = self.checksums.get(game)
# no action required if cached version is new enough
if (not remote_checksum and (remote_version > cached_version or remote_version == 0)) \
or remote_checksum != cached_checksum:
local_version: int = network_data_package["games"].get(game, {}).get("version", 0)
local_checksum: typing.Optional[str] = network_data_package["games"].get(game, {}).get("checksum")
if ((remote_checksum or remote_version <= local_version and remote_version != 0)
and remote_checksum == local_checksum):
self.update_game(network_data_package["games"][game], game)
else:
self.update_game(cached_game, game)
cached_game = Utils.load_data_package_for_checksum(game, remote_checksum)
cache_version: int = cached_game.get("version", 0)
cache_checksum: typing.Optional[str] = cached_game.get("checksum")
# download remote version if cache is not new enough
if (not remote_checksum and (remote_version > cache_version or remote_version == 0)) \
or remote_checksum != cache_checksum:
needed_updates.add(game)
else:
self.update_game(cached_game, game)
if needed_updates:
await self.send_msgs([{"cmd": "GetDataPackage", "games": [game_name]} for game_name in needed_updates])
def update_game(self, game_package: dict, game: str):
self.item_names.update_game(game, game_package["item_name_to_id"])
self.location_names.update_game(game, game_package["location_name_to_id"])
self.versions[game] = game_package.get("version", 0)
self.checksums[game] = game_package.get("checksum")
def update_data_package(self, data_package: dict):
for game, game_data in data_package["games"].items():
@ -608,6 +658,7 @@ class CommonContext:
logger.info(f"DeathLink: Received from {data['source']}")
async def send_death(self, death_text: str = ""):
"""Helper function to send a deathlink using death_text as the unique death cause string."""
if self.server and self.server.socket:
logger.info("DeathLink: Sending death to your friends...")
self.last_death_link = time.time()
@ -621,6 +672,7 @@ class CommonContext:
}])
async def update_death_link(self, death_link: bool):
"""Helper function to set Death Link connection tag on/off and update the connection if already connected."""
old_tags = self.tags.copy()
if death_link:
self.tags.add("DeathLink")
@ -630,7 +682,7 @@ class CommonContext:
await self.send_msgs([{"cmd": "ConnectUpdate", "tags": self.tags}])
def gui_error(self, title: str, text: typing.Union[Exception, str]) -> typing.Optional["kvui.MessageBox"]:
"""Displays an error messagebox"""
"""Displays an error messagebox in the loaded Kivy UI. Override if using a different UI framework"""
if not self.ui:
return None
title = title or "Error"
@ -657,21 +709,36 @@ class CommonContext:
logger.exception(msg, exc_info=exc_info, extra={'compact_gui': True})
self._messagebox_connection_loss = self.gui_error(msg, exc_info[1])
def run_gui(self):
"""Import kivy UI system and start running it as self.ui_task."""
def make_gui(self) -> "type[kvui.GameManager]":
"""
To return the Kivy `App` class needed for `run_gui` so it can be overridden before being built
Common changes are changing `base_title` to update the window title of the client and
updating `logging_pairs` to automatically make new tabs that can be filled with their respective logger.
ex. `logging_pairs.append(("Foo", "Bar"))`
will add a "Bar" tab which follows the logger returned from `logging.getLogger("Foo")`
"""
from kvui import GameManager
class TextManager(GameManager):
logging_pairs = [
("Client", "Archipelago")
]
base_title = "Archipelago Text Client"
self.ui = TextManager(self)
return TextManager
def run_gui(self):
"""Import kivy UI system from make_gui() and start running it as self.ui_task."""
ui_class = self.make_gui()
self.ui = ui_class(self)
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
def run_cli(self):
if sys.stdin:
if sys.stdin.fileno() != 0:
from multiprocessing import parent_process
if parent_process():
return # ignore MultiProcessing pipe
# steam overlay breaks when starting console_loop
if 'gameoverlayrenderer' in os.environ.get('LD_PRELOAD', ''):
logger.info("Skipping terminal input, due to conflicting Steam Overlay detected. Please use GUI only.")
@ -859,7 +926,8 @@ async def process_server_cmd(ctx: CommonContext, args: dict):
ctx.team = args["team"]
ctx.slot = args["slot"]
# int keys get lost in JSON transfer
ctx.slot_info = {int(pid): data for pid, data in args["slot_info"].items()}
ctx.slot_info = {0: NetworkSlot("Archipelago", "Archipelago", SlotType.player)}
ctx.slot_info.update({int(pid): data for pid, data in args["slot_info"].items()})
ctx.hint_points = args.get("hint_points", 0)
ctx.consume_players_package(args["players"])
ctx.stored_data_notification_keys.add(f"_read_hints_{ctx.team}_{ctx.slot}")
@ -979,6 +1047,7 @@ async def console_loop(ctx: CommonContext):
def get_base_parser(description: typing.Optional[str] = None):
"""Base argument parser to be reused for components subclassing off of CommonClient"""
import argparse
parser = argparse.ArgumentParser(description=description)
parser.add_argument('--connect', default=None, help='Address of the multiworld host.')
@ -988,7 +1057,33 @@ def get_base_parser(description: typing.Optional[str] = None):
return parser
def run_as_textclient():
def handle_url_arg(args: "argparse.Namespace",
parser: "typing.Optional[argparse.ArgumentParser]" = None) -> "argparse.Namespace":
"""
Parse the url arg "archipelago://name:pass@host:port" from launcher into correct launch args for CommonClient
If alternate data is required the urlparse response is saved back to args.url if valid
"""
if not args.url:
return args
url = urllib.parse.urlparse(args.url)
if url.scheme != "archipelago":
if not parser:
parser = get_base_parser()
parser.error(f"bad url, found {args.url}, expected url in form of archipelago://archipelago.gg:38281")
return args
args.url = url
args.connect = url.netloc
if url.username:
args.name = urllib.parse.unquote(url.username)
if url.password:
args.password = urllib.parse.unquote(url.password)
return args
def run_as_textclient(*args):
class TextContext(CommonContext):
# Text Mode to use !hint and such with games that have no text entry
tags = CommonContext.tags | {"TextOnly"}
@ -1027,16 +1122,11 @@ def run_as_textclient():
parser = get_base_parser(description="Gameless Archipelago Client, for text interfacing.")
parser.add_argument('--name', default=None, help="Slot Name to connect as.")
parser.add_argument("url", nargs="?", help="Archipelago connection url")
args = parser.parse_args()
args = parser.parse_args(args)
if args.url:
url = urllib.parse.urlparse(args.url)
args.connect = url.netloc
if url.username:
args.name = urllib.parse.unquote(url.username)
if url.password:
args.password = urllib.parse.unquote(url.password)
args = handle_url_arg(args, parser=parser)
# use colorama to display colored text highlighting on windows
colorama.init()
asyncio.run(main(args))
@ -1045,4 +1135,4 @@ def run_as_textclient():
if __name__ == '__main__':
logging.getLogger().setLevel(logging.INFO) # force log-level to work around log level resetting to WARNING
run_as_textclient()
run_as_textclient(*sys.argv[1:]) # default value for parse_args

156
Fill.py
View File

@ -12,7 +12,12 @@ from worlds.generic.Rules import add_item_rule
class FillError(RuntimeError):
pass
def __init__(self, *args: typing.Union[str, typing.Any], **kwargs) -> None:
if "multiworld" in kwargs and isinstance(args[0], str):
placements = (args[0] + f"\nAll Placements:\n" +
f"{[(loc, loc.item) for loc in kwargs['multiworld'].get_filled_locations()]}")
args = (placements, *args[1:])
super().__init__(*args)
def _log_fill_progress(name: str, placed: int, total_items: int) -> None:
@ -24,14 +29,15 @@ def sweep_from_pool(base_state: CollectionState, itempool: typing.Sequence[Item]
new_state = base_state.copy()
for item in itempool:
new_state.collect(item, True)
new_state.sweep_for_events(locations=locations)
new_state.sweep_for_advancements(locations=locations)
return new_state
def fill_restrictive(multiworld: MultiWorld, base_state: CollectionState, locations: typing.List[Location],
item_pool: typing.List[Item], single_player_placement: bool = False, lock: bool = False,
swap: bool = True, on_place: typing.Optional[typing.Callable[[Location], None]] = None,
allow_partial: bool = False, allow_excluded: bool = False, name: str = "Unknown") -> None:
allow_partial: bool = False, allow_excluded: bool = False, one_item_per_player: bool = True,
name: str = "Unknown") -> None:
"""
:param multiworld: Multiworld to be filled.
:param base_state: State assumed before fill.
@ -58,14 +64,22 @@ def fill_restrictive(multiworld: MultiWorld, base_state: CollectionState, locati
placed = 0
while any(reachable_items.values()) and locations:
# grab one item per player
items_to_place = [items.pop()
for items in reachable_items.values() if items]
if one_item_per_player:
# grab one item per player
items_to_place = [items.pop()
for items in reachable_items.values() if items]
else:
next_player = multiworld.random.choice([player for player, items in reachable_items.items() if items])
items_to_place = []
if item_pool:
items_to_place.append(reachable_items[next_player].pop())
for item in items_to_place:
for p, pool_item in enumerate(item_pool):
if pool_item is item:
item_pool.pop(p)
break
maximum_exploration_state = sweep_from_pool(
base_state, item_pool + unplaced_items, multiworld.get_filled_locations(item.player)
if single_player_placement else None)
@ -212,7 +226,7 @@ def fill_restrictive(multiworld: MultiWorld, base_state: CollectionState, locati
f"Unfilled locations:\n"
f"{', '.join(str(location) for location in locations)}\n"
f"Already placed {len(placements)}:\n"
f"{', '.join(str(place) for place in placements)}")
f"{', '.join(str(place) for place in placements)}", multiworld=multiworld)
item_pool.extend(unplaced_items)
@ -221,18 +235,30 @@ def remaining_fill(multiworld: MultiWorld,
locations: typing.List[Location],
itempool: typing.List[Item],
name: str = "Remaining",
move_unplaceable_to_start_inventory: bool = False) -> None:
move_unplaceable_to_start_inventory: bool = False,
check_location_can_fill: bool = False) -> None:
unplaced_items: typing.List[Item] = []
placements: typing.List[Location] = []
swapped_items: typing.Counter[typing.Tuple[int, str]] = Counter()
total = min(len(itempool), len(locations))
placed = 0
# Optimisation: Decide whether to do full location.can_fill check (respect excluded), or only check the item rule
if check_location_can_fill:
state = CollectionState(multiworld)
def location_can_fill_item(location_to_fill: Location, item_to_fill: Item):
return location_to_fill.can_fill(state, item_to_fill, check_access=False)
else:
def location_can_fill_item(location_to_fill: Location, item_to_fill: Item):
return location_to_fill.item_rule(item_to_fill)
while locations and itempool:
item_to_place = itempool.pop()
spot_to_fill: typing.Optional[Location] = None
for i, location in enumerate(locations):
if location.item_rule(item_to_place):
if location_can_fill_item(location, item_to_place):
# popping by index is faster than removing by content,
spot_to_fill = locations.pop(i)
# skipping a scan for the element
@ -253,7 +279,7 @@ def remaining_fill(multiworld: MultiWorld,
location.item = None
placed_item.location = None
if location.item_rule(item_to_place):
if location_can_fill_item(location, item_to_place):
# Add this item to the existing placement, and
# add the old item to the back of the queue
spot_to_fill = placements.pop(i)
@ -299,7 +325,7 @@ def remaining_fill(multiworld: MultiWorld,
f"Unfilled locations:\n"
f"{', '.join(str(location) for location in locations)}\n"
f"Already placed {len(placements)}:\n"
f"{', '.join(str(place) for place in placements)}")
f"{', '.join(str(place) for place in placements)}", multiworld=multiworld)
itempool.extend(unplaced_items)
@ -324,8 +350,8 @@ def accessibility_corrections(multiworld: MultiWorld, state: CollectionState, lo
pool.append(location.item)
state.remove(location.item)
location.item = None
if location in state.events:
state.events.remove(location)
if location in state.advancements:
state.advancements.remove(location)
locations.append(location)
if pool and locations:
locations.sort(key=lambda loc: loc.progress_type != LocationProgressType.PRIORITY)
@ -358,7 +384,7 @@ def distribute_early_items(multiworld: MultiWorld,
early_priority_locations: typing.List[Location] = []
loc_indexes_to_remove: typing.Set[int] = set()
base_state = multiworld.state.copy()
base_state.sweep_for_events(locations=(loc for loc in multiworld.get_filled_locations() if loc.address is None))
base_state.sweep_for_advancements(locations=(loc for loc in multiworld.get_filled_locations() if loc.address is None))
for i, loc in enumerate(fill_locations):
if loc.can_reach(base_state):
if loc.progress_type == LocationProgressType.PRIORITY:
@ -470,28 +496,33 @@ def distribute_items_restrictive(multiworld: MultiWorld,
nonlocal lock_later
lock_later.append(location)
single_player = multiworld.players == 1 and not multiworld.groups
if prioritylocations:
# "priority fill"
fill_restrictive(multiworld, multiworld.state, prioritylocations, progitempool,
single_player_placement=multiworld.players == 1, swap=False, on_place=mark_for_locking,
name="Priority")
single_player_placement=single_player, swap=False, on_place=mark_for_locking,
name="Priority", one_item_per_player=True, allow_partial=True)
if prioritylocations:
# retry with one_item_per_player off because some priority fills can fail to fill with that optimization
fill_restrictive(multiworld, multiworld.state, prioritylocations, progitempool,
single_player_placement=single_player, swap=False, on_place=mark_for_locking,
name="Priority Retry", one_item_per_player=False)
accessibility_corrections(multiworld, multiworld.state, prioritylocations, progitempool)
defaultlocations = prioritylocations + defaultlocations
if progitempool:
# "advancement/progression fill"
if panic_method == "swap":
fill_restrictive(multiworld, multiworld.state, defaultlocations, progitempool,
swap=True,
on_place=mark_for_locking, name="Progression", single_player_placement=multiworld.players == 1)
fill_restrictive(multiworld, multiworld.state, defaultlocations, progitempool, swap=True,
name="Progression", single_player_placement=single_player)
elif panic_method == "raise":
fill_restrictive(multiworld, multiworld.state, defaultlocations, progitempool,
swap=False,
on_place=mark_for_locking, name="Progression", single_player_placement=multiworld.players == 1)
fill_restrictive(multiworld, multiworld.state, defaultlocations, progitempool, swap=False,
name="Progression", single_player_placement=single_player)
elif panic_method == "start_inventory":
fill_restrictive(multiworld, multiworld.state, defaultlocations, progitempool,
swap=False, allow_partial=True,
on_place=mark_for_locking, name="Progression", single_player_placement=multiworld.players == 1)
fill_restrictive(multiworld, multiworld.state, defaultlocations, progitempool, swap=False,
allow_partial=True, name="Progression", single_player_placement=single_player)
if progitempool:
for item in progitempool:
logging.debug(f"Moved {item} to start_inventory to prevent fill failure.")
@ -506,7 +537,9 @@ def distribute_items_restrictive(multiworld: MultiWorld,
if progitempool:
raise FillError(
f"Not enough locations for progression items. "
f"There are {len(progitempool)} more progression items than there are available locations."
f"There are {len(progitempool)} more progression items than there are available locations.\n"
f"Unfilled locations:\n{multiworld.get_unfilled_locations()}.",
multiworld=multiworld,
)
accessibility_corrections(multiworld, multiworld.state, defaultlocations)
@ -523,7 +556,8 @@ def distribute_items_restrictive(multiworld: MultiWorld,
if excludedlocations:
raise FillError(
f"Not enough filler items for excluded locations. "
f"There are {len(excludedlocations)} more excluded locations than filler or trap items."
f"There are {len(excludedlocations)} more excluded locations than excludable items.",
multiworld=multiworld,
)
restitempool = filleritempool + usefulitempool
@ -543,6 +577,26 @@ def distribute_items_restrictive(multiworld: MultiWorld,
print_data = {"items": items_counter, "locations": locations_counter}
logging.info(f"Per-Player counts: {print_data})")
more_locations = locations_counter - items_counter
more_items = items_counter - locations_counter
for player in multiworld.player_ids:
if more_locations[player]:
logging.error(
f"Player {multiworld.get_player_name(player)} had {more_locations[player]} more locations than items.")
elif more_items[player]:
logging.warning(
f"Player {multiworld.get_player_name(player)} had {more_items[player]} more items than locations.")
if unfilled:
raise FillError(
f"Unable to fill all locations.\n" +
f"Unfilled locations({len(unfilled)}): {unfilled}"
)
else:
logging.warning(
f"Unable to place all items.\n" +
f"Unplaced items({len(unplaced)}): {unplaced}"
)
def flood_items(multiworld: MultiWorld) -> None:
# get items to distribute
@ -551,7 +605,7 @@ def flood_items(multiworld: MultiWorld) -> None:
progress_done = False
# sweep once to pick up preplaced items
multiworld.state.sweep_for_events()
multiworld.state.sweep_for_advancements()
# fill multiworld from top of itempool while we can
while not progress_done:
@ -589,7 +643,7 @@ def flood_items(multiworld: MultiWorld) -> None:
if candidate_item_to_place is not None:
item_to_place = candidate_item_to_place
else:
raise FillError('No more progress items left to place.')
raise FillError('No more progress items left to place.', multiworld=multiworld)
# find item to replace with progress item
location_list = multiworld.get_reachable_locations()
@ -646,7 +700,6 @@ def balance_multiworld_progression(multiworld: MultiWorld) -> None:
def get_sphere_locations(sphere_state: CollectionState,
locations: typing.Set[Location]) -> typing.Set[Location]:
sphere_state.sweep_for_events(key_only=True, locations=locations)
return {loc for loc in locations if sphere_state.can_reach(loc)}
def item_percentage(player: int, num: int) -> float:
@ -740,7 +793,7 @@ def balance_multiworld_progression(multiworld: MultiWorld) -> None:
), items_to_test):
reducing_state.collect(location.item, True, location)
reducing_state.sweep_for_events(locations=locations_to_test)
reducing_state.sweep_for_advancements(locations=locations_to_test)
if multiworld.has_beaten_game(balancing_state):
if not multiworld.has_beaten_game(reducing_state):
@ -823,7 +876,7 @@ def distribute_planned(multiworld: MultiWorld) -> None:
warn(warning, force)
swept_state = multiworld.state.copy()
swept_state.sweep_for_events()
swept_state.sweep_for_advancements()
reachable = frozenset(multiworld.get_reachable_locations(swept_state))
early_locations: typing.Dict[int, typing.List[str]] = collections.defaultdict(list)
non_early_locations: typing.Dict[int, typing.List[str]] = collections.defaultdict(list)
@ -974,15 +1027,32 @@ def distribute_planned(multiworld: MultiWorld) -> None:
multiworld.random.shuffle(items)
count = 0
err: typing.List[str] = []
successful_pairs: typing.List[typing.Tuple[Item, Location]] = []
successful_pairs: typing.List[typing.Tuple[int, Item, Location]] = []
claimed_indices: typing.Set[typing.Optional[int]] = set()
for item_name in items:
item = multiworld.worlds[player].create_item(item_name)
index_to_delete: typing.Optional[int] = None
if from_pool:
try:
# If from_pool, try to find an existing item with this name & player in the itempool and use it
index_to_delete, item = next(
(i, item) for i, item in enumerate(multiworld.itempool)
if item.player == player and item.name == item_name and i not in claimed_indices
)
except StopIteration:
warn(
f"Could not remove {item_name} from pool for {multiworld.player_name[player]} as it's already missing from it.",
placement['force'])
item = multiworld.worlds[player].create_item(item_name)
else:
item = multiworld.worlds[player].create_item(item_name)
for location in reversed(candidates):
if (location.address is None) == (item.code is None): # either both None or both not None
if not location.item:
if location.item_rule(item):
if location.can_fill(multiworld.state, item, False):
successful_pairs.append((item, location))
successful_pairs.append((index_to_delete, item, location))
claimed_indices.add(index_to_delete)
candidates.remove(location)
count = count + 1
break
@ -994,6 +1064,7 @@ def distribute_planned(multiworld: MultiWorld) -> None:
err.append(f"Cannot place {item_name} into already filled location {location}.")
else:
err.append(f"Mismatch between {item_name} and {location}, only one is an event.")
if count == maxcount:
break
if count < placement['count']['min']:
@ -1001,17 +1072,16 @@ def distribute_planned(multiworld: MultiWorld) -> None:
failed(
f"Plando block failed to place {m - count} of {m} item(s) for {multiworld.player_name[player]}, error(s): {' '.join(err)}",
placement['force'])
for (item, location) in successful_pairs:
# Sort indices in reverse so we can remove them one by one
successful_pairs = sorted(successful_pairs, key=lambda successful_pair: successful_pair[0] or 0, reverse=True)
for (index, item, location) in successful_pairs:
multiworld.push_item(location, item, collect=False)
location.locked = True
logging.debug(f"Plando placed {item} at {location}")
if from_pool:
try:
multiworld.itempool.remove(item)
except ValueError:
warn(
f"Could not remove {item} from pool for {multiworld.player_name[player]} as it's already missing from it.",
placement['force'])
if index is not None: # If this item is from_pool and was found in the pool, remove it.
multiworld.itempool.pop(index)
except Exception as e:
raise Exception(

View File

@ -42,11 +42,13 @@ def mystery_argparse():
help="Path to output folder. Absolute or relative to cwd.") # absolute or relative to cwd
parser.add_argument('--race', action='store_true', default=defaults.race)
parser.add_argument('--meta_file_path', default=defaults.meta_file_path)
parser.add_argument('--log_level', default='info', help='Sets log level')
parser.add_argument('--yaml_output', default=0, type=lambda value: max(int(value), 0),
help='Output rolled mystery results to yaml up to specified number (made for async multiworld)')
parser.add_argument('--plando', default=defaults.plando_options,
help='List of options that can be set manually. Can be combined, for example "bosses, items"')
parser.add_argument('--log_level', default=defaults.loglevel, help='Sets log level')
parser.add_argument('--log_time', help="Add timestamps to STDOUT",
default=defaults.logtime, action='store_true')
parser.add_argument("--csv_output", action="store_true",
help="Output rolled player options to csv (made for async multiworld).")
parser.add_argument("--plando", default=defaults.plando_options,
help="List of options that can be set manually. Can be combined, for example \"bosses, items\"")
parser.add_argument("--skip_prog_balancing", action="store_true",
help="Skip progression balancing step during generation.")
parser.add_argument("--skip_output", action="store_true",
@ -65,15 +67,17 @@ def get_seed_name(random_source) -> str:
return f"{random_source.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits)
def main(args=None):
def main(args=None) -> Tuple[argparse.Namespace, int]:
# __name__ == "__main__" check so unittests that already imported worlds don't trip this.
if __name__ == "__main__" and "worlds" in sys.modules:
raise Exception("Worlds system should not be loaded before logging init.")
if not args:
args = mystery_argparse()
seed = get_seed(args.seed)
# __name__ == "__main__" check so unittests that already imported worlds don't trip this.
if __name__ == "__main__" and "worlds" in sys.modules:
raise Exception("Worlds system should not be loaded before logging init.")
Utils.init_logging(f"Generate_{seed}", loglevel=args.log_level)
Utils.init_logging(f"Generate_{seed}", loglevel=args.log_level, add_timestamp=args.log_time)
random.seed(seed)
seed_name = get_seed_name(random)
@ -108,11 +112,18 @@ def main(args=None):
player_files = {}
for file in os.scandir(args.player_files_path):
fname = file.name
if file.is_file() and not fname.startswith(".") and \
if file.is_file() and not fname.startswith(".") and not fname.lower().endswith(".ini") and \
os.path.join(args.player_files_path, fname) not in {args.meta_file_path, args.weights_file_path}:
path = os.path.join(args.player_files_path, fname)
try:
weights_cache[fname] = read_weights_yamls(path)
weights_for_file = []
for doc_idx, yaml in enumerate(read_weights_yamls(path)):
if yaml is None:
logging.warning(f"Ignoring empty yaml document #{doc_idx + 1} in {fname}")
else:
weights_for_file.append(yaml)
weights_cache[fname] = tuple(weights_for_file)
except Exception as e:
raise ValueError(f"File {fname} is invalid. Please fix your yaml.") from e
@ -153,6 +164,8 @@ def main(args=None):
erargs.outputpath = args.outputpath
erargs.skip_prog_balancing = args.skip_prog_balancing
erargs.skip_output = args.skip_output
erargs.name = {}
erargs.csv_output = args.csv_output
settings_cache: Dict[str, Tuple[argparse.Namespace, ...]] = \
{fname: (tuple(roll_settings(yaml, args.plando) for yaml in yamls) if args.sameoptions else None)
@ -200,7 +213,7 @@ def main(args=None):
if path == args.weights_file_path: # if name came from the weights file, just use base player name
erargs.name[player] = f"Player{player}"
elif not erargs.name[player]: # if name was not specified, generate it from filename
elif player not in erargs.name: # if name was not specified, generate it from filename
erargs.name[player] = os.path.splitext(os.path.split(path)[-1])[0]
erargs.name[player] = handle_name(erargs.name[player], player, name_counter)
@ -213,30 +226,7 @@ def main(args=None):
if len(set(name.lower() for name in erargs.name.values())) != len(erargs.name):
raise Exception(f"Names have to be unique. Names: {Counter(name.lower() for name in erargs.name.values())}")
if args.yaml_output:
import yaml
important = {}
for option, player_settings in vars(erargs).items():
if type(player_settings) == dict:
if all(type(value) != list for value in player_settings.values()):
if len(player_settings.values()) > 1:
important[option] = {player: value for player, value in player_settings.items() if
player <= args.yaml_output}
else:
logging.debug(f"No player settings defined for option '{option}'")
else:
if player_settings != "": # is not empty name
important[option] = player_settings
else:
logging.debug(f"No player settings defined for option '{option}'")
if args.outputpath:
os.makedirs(args.outputpath, exist_ok=True)
with open(os.path.join(args.outputpath if args.outputpath else ".", f"generate_{seed_name}.yaml"), "wt") as f:
yaml.dump(important, f)
from Main import main as ERmain
return ERmain(erargs, seed)
return erargs, seed
def read_weights_yamls(path) -> Tuple[Any, ...]:
@ -450,7 +440,7 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b
if "linked_options" in weights:
weights = roll_linked_options(weights)
valid_keys = set()
valid_keys = {"triggers"}
if "triggers" in weights:
weights = roll_triggers(weights, weights["triggers"], valid_keys)
@ -472,6 +462,10 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b
raise Exception(f"Option {option_key} has to be in a game's section, not on its own.")
ret.game = get_choice("game", weights)
if not isinstance(ret.game, str):
if ret.game is None:
raise Exception('"game" not specified')
raise Exception(f"Invalid game: {ret.game}")
if ret.game not in AutoWorldRegister.world_types:
from worlds import failed_world_loads
picks = Utils.get_fuzzy_results(ret.game, list(AutoWorldRegister.world_types) + failed_world_loads, limit=1)[0]
@ -505,15 +499,23 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b
for option_key, option in world_type.options_dataclass.type_hints.items():
handle_option(ret, game_weights, option_key, option, plando_options)
valid_keys.add(option_key)
for option_key in game_weights:
if option_key in {"triggers", *valid_keys}:
continue
logging.warning(f"{option_key} is not a valid option name for {ret.game} and is not present in triggers.")
# TODO remove plando_items after moving it to the options system
valid_keys.add("plando_items")
if PlandoOptions.items in plando_options:
ret.plando_items = game_weights.get("plando_items", [])
ret.plando_items = copy.deepcopy(game_weights.get("plando_items", []))
if ret.game == "A Link to the Past":
# TODO there are still more LTTP options not on the options system
valid_keys |= {"sprite_pool", "sprite", "random_sprite_on_event"}
roll_alttp_settings(ret, game_weights)
# log a warning for options within a game section that aren't determined as valid
for option_key in game_weights:
if option_key in valid_keys:
continue
logging.warning(f"{option_key} is not a valid option name for {ret.game} and is not present in triggers "
f"for player {ret.name}.")
return ret
@ -545,7 +547,9 @@ def roll_alttp_settings(ret: argparse.Namespace, weights):
if __name__ == '__main__':
import atexit
confirmation = atexit.register(input, "Press enter to close.")
multiworld = main()
erargs, seed = main()
from Main import main as ERmain
multiworld = ERmain(erargs, seed)
if __debug__:
import gc
import sys

9
KH1Client.py Normal file
View File

@ -0,0 +1,9 @@
if __name__ == '__main__':
import ModuleUpdate
ModuleUpdate.update()
import Utils
Utils.init_logging("KH1Client", exception_logger="Client")
from worlds.kh1.Client import launch
launch()

View File

@ -1,7 +1,7 @@
MIT License
Copyright (c) 2017 LLCoolDave
Copyright (c) 2022 Berserker66
Copyright (c) 2025 Berserker66
Copyright (c) 2022 CaitSith2
Copyright (c) 2021 LegendaryLinux

View File

@ -16,25 +16,27 @@ import multiprocessing
import shlex
import subprocess
import sys
import urllib.parse
import webbrowser
from os.path import isfile
from shutil import which
from typing import Callable, Sequence, Union, Optional
import Utils
import settings
from worlds.LauncherComponents import Component, components, Type, SuffixIdentifier, icon_paths
from typing import Callable, Optional, Sequence, Tuple, Union
if __name__ == "__main__":
import ModuleUpdate
ModuleUpdate.update()
from Utils import is_frozen, user_path, local_path, init_logging, open_filename, messagebox, \
is_windows, is_macos, is_linux
import settings
import Utils
from Utils import (init_logging, is_frozen, is_linux, is_macos, is_windows, local_path, messagebox, open_filename,
user_path)
from worlds.LauncherComponents import Component, components, icon_paths, SuffixIdentifier, Type
def open_host_yaml():
file = settings.get_settings().filename
s = settings.get_settings()
file = s.filename
s.save()
assert file, "host.yaml missing"
if is_linux:
exe = which('sensible-editor') or which('gedit') or \
@ -101,13 +103,71 @@ components.extend([
Component("Open host.yaml", func=open_host_yaml),
Component("Open Patch", func=open_patch),
Component("Generate Template Options", func=generate_yamls),
Component("Archipelago Website", func=lambda: webbrowser.open("https://archipelago.gg/")),
Component("Discord Server", icon="discord", func=lambda: webbrowser.open("https://discord.gg/8Z65BR2")),
Component("Unrated/18+ Discord Server", icon="discord", func=lambda: webbrowser.open("https://discord.gg/fqvNCCRsu4")),
Component("Browse Files", func=browse_files),
])
def identify(path: Union[None, str]):
def handle_uri(path: str, launch_args: Tuple[str, ...]) -> None:
url = urllib.parse.urlparse(path)
queries = urllib.parse.parse_qs(url.query)
launch_args = (path, *launch_args)
client_component = None
text_client_component = None
if "game" in queries:
game = queries["game"][0]
else: # TODO around 0.6.0 - this is for pre this change webhost uri's
game = "Archipelago"
for component in components:
if component.supports_uri and component.game_name == game:
client_component = component
elif component.display_name == "Text Client":
text_client_component = component
if client_component is None:
run_component(text_client_component, *launch_args)
return
from kvui import App, Button, BoxLayout, Label, Window
class Popup(App):
def __init__(self):
self.title = "Connect to Multiworld"
self.icon = r"data/icon.png"
super().__init__()
def build(self):
layout = BoxLayout(orientation="vertical")
layout.add_widget(Label(text="Select client to open and connect with."))
button_row = BoxLayout(orientation="horizontal", size_hint=(1, 0.4))
text_client_button = Button(
text=text_client_component.display_name,
on_release=lambda *args: run_component(text_client_component, *launch_args)
)
button_row.add_widget(text_client_button)
game_client_button = Button(
text=client_component.display_name,
on_release=lambda *args: run_component(client_component, *launch_args)
)
button_row.add_widget(game_client_button)
layout.add_widget(button_row)
return layout
def _stop(self, *largs):
# see run_gui Launcher _stop comment for details
self.root_window.close()
super()._stop(*largs)
Popup().run()
def identify(path: Union[None, str]) -> Tuple[Union[None, str], Union[None, Component]]:
if path is None:
return None, None
for component in components:
@ -164,9 +224,8 @@ refresh_components: Optional[Callable[[], None]] = None
def run_gui():
from kvui import App, ContainerLayout, GridLayout, Button, Label, ScrollBox, Widget
from kvui import App, ContainerLayout, GridLayout, Button, Label, ScrollBox, Widget, ApAsyncImage
from kivy.core.window import Window
from kivy.uix.image import AsyncImage
from kivy.uix.relativelayout import RelativeLayout
class Launcher(App):
@ -177,7 +236,7 @@ def run_gui():
_client_layout: Optional[ScrollBox] = None
def __init__(self, ctx=None):
self.title = self.base_title
self.title = self.base_title + " " + Utils.__version__
self.ctx = ctx
self.icon = r"data/icon.png"
super().__init__()
@ -199,8 +258,8 @@ def run_gui():
button.component = component
button.bind(on_release=self.component_action)
if component.icon != "icon":
image = AsyncImage(source=icon_paths[component.icon],
size=(38, 38), size_hint=(None, 1), pos=(5, 0))
image = ApAsyncImage(source=icon_paths[component.icon],
size=(38, 38), size_hint=(None, 1), pos=(5, 0))
box_layout = RelativeLayout(size_hint_y=None, height=40)
box_layout.add_widget(button)
box_layout.add_widget(image)
@ -266,7 +325,7 @@ def run_gui():
if file and component:
run_component(component, file)
else:
logging.warning(f"unable to identify component for {filename}")
logging.warning(f"unable to identify component for {file}")
def _stop(self, *largs):
# ran into what appears to be https://groups.google.com/g/kivy-users/c/saWDLoYCSZ4 with PyCharm.
@ -299,20 +358,24 @@ def main(args: Optional[Union[argparse.Namespace, dict]] = None):
elif not args:
args = {}
if args.get("Patch|Game|Component", None) is not None:
file, component = identify(args["Patch|Game|Component"])
path = args.get("Patch|Game|Component|url", None)
if path is not None:
if path.startswith("archipelago://"):
handle_uri(path, args.get("args", ()))
return
file, component = identify(path)
if file:
args['file'] = file
if component:
args['component'] = component
if not component:
logging.warning(f"Could not identify Component responsible for {args['Patch|Game|Component']}")
logging.warning(f"Could not identify Component responsible for {path}")
if args["update_settings"]:
update_settings()
if 'file' in args:
if "file" in args:
run_component(args["component"], args["file"], *args["args"])
elif 'component' in args:
elif "component" in args:
run_component(args["component"], *args["args"])
elif not args["update_settings"]:
run_gui()
@ -322,12 +385,16 @@ if __name__ == '__main__':
init_logging('Launcher')
Utils.freeze_support()
multiprocessing.set_start_method("spawn") # if launched process uses kivy, fork won't work
parser = argparse.ArgumentParser(description='Archipelago Launcher')
parser = argparse.ArgumentParser(
description='Archipelago Launcher',
usage="[-h] [--update_settings] [Patch|Game|Component] [-- component args here]"
)
run_group = parser.add_argument_group("Run")
run_group.add_argument("--update_settings", action="store_true",
help="Update host.yaml and exit.")
run_group.add_argument("Patch|Game|Component", type=str, nargs="?",
help="Pass either a patch file, a generated game or the name of a component to run.")
run_group.add_argument("Patch|Game|Component|url", type=str, nargs="?",
help="Pass either a patch file, a generated game, the component name to run, or a url to "
"connect with.")
run_group.add_argument("args", nargs="*",
help="Arguments to pass to component.")
main(parser.parse_args())

View File

@ -235,7 +235,7 @@ class RAGameboy():
def check_command_response(self, command: str, response: bytes):
if command == "VERSION":
ok = re.match("\d+\.\d+\.\d+", response.decode('ascii')) is not None
ok = re.match(r"\d+\.\d+\.\d+", response.decode('ascii')) is not None
else:
ok = response.startswith(command.encode())
if not ok:
@ -467,6 +467,8 @@ class LinksAwakeningContext(CommonContext):
def __init__(self, server_address: typing.Optional[str], password: typing.Optional[str], magpie: typing.Optional[bool]) -> None:
self.client = LinksAwakeningClient()
self.slot_data = {}
if magpie:
self.magpie_enabled = True
self.magpie = MagpieBridge()
@ -558,12 +560,18 @@ class LinksAwakeningContext(CommonContext):
while self.client.auth == None:
await asyncio.sleep(0.1)
# Just return if we're closing
if self.exit_event.is_set():
return
self.auth = self.client.auth
await self.send_connect()
def on_package(self, cmd: str, args: dict):
if cmd == "Connected":
self.game = self.slot_info[self.slot].game
self.slot_data = args.get("slot_data", {})
# TODO - use watcher_event
if cmd == "ReceivedItems":
for index, item in enumerate(args["items"], start=args["index"]):
@ -628,6 +636,7 @@ class LinksAwakeningContext(CommonContext):
self.magpie.set_checks(self.client.tracker.all_checks)
await self.magpie.set_item_tracker(self.client.item_tracker)
await self.magpie.send_gps(self.client.gps_tracker)
self.magpie.slot_data = self.slot_data
except Exception:
# Don't let magpie errors take out the client
pass

View File

@ -14,7 +14,7 @@ import tkinter as tk
from argparse import Namespace
from concurrent.futures import as_completed, ThreadPoolExecutor
from glob import glob
from tkinter import Tk, Frame, Label, StringVar, Entry, filedialog, messagebox, Button, Radiobutton, LEFT, X, TOP, LabelFrame, \
from tkinter import Tk, Frame, Label, StringVar, Entry, filedialog, messagebox, Button, Radiobutton, LEFT, X, BOTH, TOP, LabelFrame, \
IntVar, Checkbutton, E, W, OptionMenu, Toplevel, BOTTOM, RIGHT, font as font, PhotoImage
from tkinter.constants import DISABLED, NORMAL
from urllib.parse import urlparse
@ -29,7 +29,8 @@ from Utils import output_path, local_path, user_path, open_file, get_cert_none_s
GAME_ALTTP = "A Link to the Past"
WINDOW_MIN_HEIGHT = 525
WINDOW_MIN_WIDTH = 425
class AdjusterWorld(object):
def __init__(self, sprite_pool):
@ -242,16 +243,17 @@ def adjustGUI():
from argparse import Namespace
from Utils import __version__ as MWVersion
adjustWindow = Tk()
adjustWindow.minsize(WINDOW_MIN_WIDTH, WINDOW_MIN_HEIGHT)
adjustWindow.wm_title("Archipelago %s LttP Adjuster" % MWVersion)
set_icon(adjustWindow)
rom_options_frame, rom_vars, set_sprite = get_rom_options_frame(adjustWindow)
bottomFrame2 = Frame(adjustWindow)
bottomFrame2 = Frame(adjustWindow, padx=8, pady=2)
romFrame, romVar = get_rom_frame(adjustWindow)
romDialogFrame = Frame(adjustWindow)
romDialogFrame = Frame(adjustWindow, padx=8, pady=2)
baseRomLabel2 = Label(romDialogFrame, text='Rom to adjust')
romVar2 = StringVar()
romEntry2 = Entry(romDialogFrame, textvariable=romVar2)
@ -261,9 +263,9 @@ def adjustGUI():
romVar2.set(rom)
romSelectButton2 = Button(romDialogFrame, text='Select Rom', command=RomSelect2)
romDialogFrame.pack(side=TOP, expand=True, fill=X)
baseRomLabel2.pack(side=LEFT)
romEntry2.pack(side=LEFT, expand=True, fill=X)
romDialogFrame.pack(side=TOP, expand=False, fill=X)
baseRomLabel2.pack(side=LEFT, expand=False, fill=X, padx=(0, 8))
romEntry2.pack(side=LEFT, expand=True, fill=BOTH, pady=1)
romSelectButton2.pack(side=LEFT)
def adjustRom():
@ -331,12 +333,11 @@ def adjustGUI():
messagebox.showinfo(title="Success", message="Settings saved to persistent storage")
adjustButton = Button(bottomFrame2, text='Adjust Rom', command=adjustRom)
rom_options_frame.pack(side=TOP)
rom_options_frame.pack(side=TOP, padx=8, pady=8, fill=BOTH, expand=True)
adjustButton.pack(side=LEFT, padx=(5,5))
saveButton = Button(bottomFrame2, text='Save Settings', command=saveGUISettings)
saveButton.pack(side=LEFT, padx=(5,5))
bottomFrame2.pack(side=TOP, pady=(5,5))
tkinter_center_window(adjustWindow)
@ -576,7 +577,7 @@ class AttachTooltip(object):
def get_rom_frame(parent=None):
adjuster_settings = get_adjuster_settings(GAME_ALTTP)
romFrame = Frame(parent)
romFrame = Frame(parent, padx=8, pady=8)
baseRomLabel = Label(romFrame, text='LttP Base Rom: ')
romVar = StringVar(value=adjuster_settings.baserom)
romEntry = Entry(romFrame, textvariable=romVar)
@ -596,20 +597,19 @@ def get_rom_frame(parent=None):
romSelectButton = Button(romFrame, text='Select Rom', command=RomSelect)
baseRomLabel.pack(side=LEFT)
romEntry.pack(side=LEFT, expand=True, fill=X)
romEntry.pack(side=LEFT, expand=True, fill=BOTH, pady=1)
romSelectButton.pack(side=LEFT)
romFrame.pack(side=TOP, expand=True, fill=X)
romFrame.pack(side=TOP, fill=X)
return romFrame, romVar
def get_rom_options_frame(parent=None):
adjuster_settings = get_adjuster_settings(GAME_ALTTP)
romOptionsFrame = LabelFrame(parent, text="Rom options")
romOptionsFrame.columnconfigure(0, weight=1)
romOptionsFrame.columnconfigure(1, weight=1)
romOptionsFrame = LabelFrame(parent, text="Rom options", padx=8, pady=8)
for i in range(5):
romOptionsFrame.rowconfigure(i, weight=1)
romOptionsFrame.rowconfigure(i, weight=0, pad=4)
vars = Namespace()
vars.MusicVar = IntVar()
@ -660,7 +660,7 @@ def get_rom_options_frame(parent=None):
spriteSelectButton = Button(spriteDialogFrame, text='...', command=SpriteSelect)
baseSpriteLabel.pack(side=LEFT)
spriteEntry.pack(side=LEFT)
spriteEntry.pack(side=LEFT, expand=True, fill=X)
spriteSelectButton.pack(side=LEFT)
oofDialogFrame = Frame(romOptionsFrame)

177
Main.py
View File

@ -11,7 +11,8 @@ from typing import Dict, List, Optional, Set, Tuple, Union
import worlds
from BaseClasses import CollectionState, Item, Location, LocationProgressType, MultiWorld, Region
from Fill import balance_multiworld_progression, distribute_items_restrictive, distribute_planned, flood_items
from Fill import FillError, balance_multiworld_progression, distribute_items_restrictive, distribute_planned, \
flood_items
from Options import StartInventoryPool
from Utils import __version__, output_path, version_tuple, get_settings
from settings import get_settings
@ -45,6 +46,9 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
multiworld.sprite_pool = args.sprite_pool.copy()
multiworld.set_options(args)
if args.csv_output:
from Options import dump_player_options
dump_player_options(multiworld)
multiworld.set_item_links()
multiworld.state = CollectionState(multiworld)
logger.info('Archipelago Version %s - Seed: %s\n', __version__, multiworld.seed)
@ -100,7 +104,7 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
multiworld.early_items[player][item_name] = max(0, early-count)
remaining_count = count-early
if remaining_count > 0:
local_early = multiworld.early_local_items[player].get(item_name, 0)
local_early = multiworld.local_early_items[player].get(item_name, 0)
if local_early:
multiworld.early_items[player][item_name] = max(0, local_early - remaining_count)
del local_early
@ -124,14 +128,19 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
for player in multiworld.player_ids:
exclusion_rules(multiworld, player, multiworld.worlds[player].options.exclude_locations.value)
multiworld.worlds[player].options.priority_locations.value -= multiworld.worlds[player].options.exclude_locations.value
world_excluded_locations = set()
for location_name in multiworld.worlds[player].options.priority_locations.value:
try:
location = multiworld.get_location(location_name, player)
except KeyError as e: # failed to find the given location. Check if it's a legitimate location
if location_name not in multiworld.worlds[player].location_name_to_id:
raise Exception(f"Unable to prioritize location {location_name} in player {player}'s world.") from e
else:
except KeyError:
continue
if location.progress_type != LocationProgressType.EXCLUDED:
location.progress_type = LocationProgressType.PRIORITY
else:
logger.warning(f"Unable to prioritize location \"{location_name}\" in player {player}'s world because the world excluded it.")
world_excluded_locations.add(location_name)
multiworld.worlds[player].options.priority_locations.value -= world_excluded_locations
# Set local and non-local item rules.
if multiworld.players > 1:
@ -139,122 +148,46 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
else:
multiworld.worlds[1].options.non_local_items.value = set()
multiworld.worlds[1].options.local_items.value = set()
AutoWorld.call_all(multiworld, "connect_entrances")
AutoWorld.call_all(multiworld, "generate_basic")
# remove starting inventory from pool items.
# Because some worlds don't actually create items during create_items this has to be as late as possible.
if any(getattr(multiworld.worlds[player].options, "start_inventory_from_pool", None) for player in multiworld.player_ids):
new_items: List[Item] = []
depletion_pool: Dict[int, Dict[str, int]] = {
player: getattr(multiworld.worlds[player].options,
"start_inventory_from_pool",
StartInventoryPool({})).value.copy()
for player in multiworld.player_ids
}
for player, items in depletion_pool.items():
player_world: AutoWorld.World = multiworld.worlds[player]
for count in items.values():
for _ in range(count):
new_items.append(player_world.create_filler())
target: int = sum(sum(items.values()) for items in depletion_pool.values())
for i, item in enumerate(multiworld.itempool):
if depletion_pool[item.player].get(item.name, 0):
target -= 1
depletion_pool[item.player][item.name] -= 1
# quick abort if we have found all items
if not target:
new_items.extend(multiworld.itempool[i+1:])
break
else:
new_items.append(item)
# leftovers?
if target:
for player, remaining_items in depletion_pool.items():
remaining_items = {name: count for name, count in remaining_items.items() if count}
if remaining_items:
raise Exception(f"{multiworld.get_player_name(player)}"
f" is trying to remove items from their pool that don't exist: {remaining_items}")
assert len(multiworld.itempool) == len(new_items), "Item Pool amounts should not change."
multiworld.itempool[:] = new_items
# temporary home for item links, should be moved out of Main
for group_id, group in multiworld.groups.items():
def find_common_pool(players: Set[int], shared_pool: Set[str]) -> Tuple[
Optional[Dict[int, Dict[str, int]]], Optional[Dict[str, int]]
]:
classifications: Dict[str, int] = collections.defaultdict(int)
counters = {player: {name: 0 for name in shared_pool} for player in players}
for item in multiworld.itempool:
if item.player in counters and item.name in shared_pool:
counters[item.player][item.name] += 1
classifications[item.name] |= item.classification
for player in players.copy():
if all([counters[player][item] == 0 for item in shared_pool]):
players.remove(player)
del (counters[player])
if not players:
return None, None
for item in shared_pool:
count = min(counters[player][item] for player in players)
if count:
for player in players:
counters[player][item] = count
else:
for player in players:
del (counters[player][item])
return counters, classifications
common_item_count, classifications = find_common_pool(group["players"], group["item_pool"])
if not common_item_count:
continue
fallback_inventory = StartInventoryPool({})
depletion_pool: Dict[int, Dict[str, int]] = {
player: getattr(multiworld.worlds[player].options, "start_inventory_from_pool", fallback_inventory).value.copy()
for player in multiworld.player_ids
}
target_per_player = {
player: sum(target_items.values()) for player, target_items in depletion_pool.items() if target_items
}
if target_per_player:
new_itempool: List[Item] = []
for item_name, item_count in next(iter(common_item_count.values())).items():
for _ in range(item_count):
new_item = group["world"].create_item(item_name)
# mangle together all original classification bits
new_item.classification |= classifications[item_name]
new_itempool.append(new_item)
region = Region("Menu", group_id, multiworld, "ItemLink")
multiworld.regions.append(region)
locations = region.locations
# Make new itempool with start_inventory_from_pool items removed
for item in multiworld.itempool:
count = common_item_count.get(item.player, {}).get(item.name, 0)
if count:
loc = Location(group_id, f"Item Link: {item.name} -> {multiworld.player_name[item.player]} {count}",
None, region)
loc.access_rule = lambda state, item_name = item.name, group_id_ = group_id, count_ = count: \
state.has(item_name, group_id_, count_)
locations.append(loc)
loc.place_locked_item(item)
common_item_count[item.player][item.name] -= 1
if depletion_pool[item.player].get(item.name, 0):
depletion_pool[item.player][item.name] -= 1
else:
new_itempool.append(item)
itemcount = len(multiworld.itempool)
multiworld.itempool = new_itempool
# Create filler in place of the removed items, warn if any items couldn't be found in the multiworld itempool
for player, target in target_per_player.items():
unfound_items = {item: count for item, count in depletion_pool[player].items() if count}
while itemcount > len(multiworld.itempool):
items_to_add = []
for player in group["players"]:
if group["link_replacement"]:
item_player = group_id
else:
item_player = player
if group["replacement_items"][player]:
items_to_add.append(AutoWorld.call_single(multiworld, "create_item", item_player,
group["replacement_items"][player]))
else:
items_to_add.append(AutoWorld.call_single(multiworld, "create_filler", item_player))
multiworld.random.shuffle(items_to_add)
multiworld.itempool.extend(items_to_add[:itemcount - len(multiworld.itempool)])
if unfound_items:
player_name = multiworld.get_player_name(player)
logger.warning(f"{player_name} tried to remove items from their pool that don't exist: {unfound_items}")
needed_items = target_per_player[player] - sum(unfound_items.values())
new_itempool += [multiworld.worlds[player].create_filler() for _ in range(needed_items)]
assert len(multiworld.itempool) == len(new_itempool), "Item Pool amounts should not change."
multiworld.itempool[:] = new_itempool
multiworld.link_items()
if any(multiworld.item_links.values()):
multiworld._all_state = None
@ -310,6 +243,7 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
def write_multidata():
import NetUtils
from NetUtils import HintStatus
slot_data = {}
client_versions = {}
games = {}
@ -334,10 +268,10 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
for slot in multiworld.player_ids:
slot_data[slot] = multiworld.worlds[slot].fill_slot_data()
def precollect_hint(location):
def precollect_hint(location: Location, auto_status: HintStatus):
entrance = er_hint_data.get(location.player, {}).get(location.address, "")
hint = NetUtils.Hint(location.item.player, location.player, location.address,
location.item.code, False, entrance, location.item.flags)
location.item.code, False, entrance, location.item.flags, auto_status)
precollected_hints[location.player].add(hint)
if location.item.player not in multiworld.groups:
precollected_hints[location.item.player].add(hint)
@ -350,19 +284,22 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
if type(location.address) == int:
assert location.item.code is not None, "item code None should be event, " \
"location.address should then also be None. Location: " \
f" {location}"
f" {location}, Item: {location.item}"
assert location.address not in locations_data[location.player], (
f"Locations with duplicate address. {location} and "
f"{locations_data[location.player][location.address]}")
locations_data[location.player][location.address] = \
location.item.code, location.item.player, location.item.flags
auto_status = HintStatus.HINT_AVOID if location.item.trap else HintStatus.HINT_PRIORITY
if location.name in multiworld.worlds[location.player].options.start_location_hints:
precollect_hint(location)
if not location.item.trap: # Unspecified status for location hints, except traps
auto_status = HintStatus.HINT_UNSPECIFIED
precollect_hint(location, auto_status)
elif location.item.name in multiworld.worlds[location.item.player].options.start_hints:
precollect_hint(location)
precollect_hint(location, auto_status)
elif any([location.item.name in multiworld.worlds[player].options.start_hints
for player in multiworld.groups.get(location.item.player, {}).get("players", [])]):
precollect_hint(location)
precollect_hint(location, auto_status)
# embedded data package
data_package = {
@ -374,11 +311,10 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
# get spheres -> filter address==None -> skip empty
spheres: List[Dict[int, Set[int]]] = []
for sphere in multiworld.get_spheres():
for sphere in multiworld.get_sendable_spheres():
current_sphere: Dict[int, Set[int]] = collections.defaultdict(set)
for sphere_location in sphere:
if type(sphere_location.address) is int:
current_sphere[sphere_location.player].add(sphere_location.address)
current_sphere[sphere_location.player].add(sphere_location.address)
if current_sphere:
spheres.append(dict(current_sphere))
@ -399,6 +335,7 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
"seed_name": multiworld.seed_name,
"spheres": spheres,
"datapackage": data_package,
"race_mode": int(multiworld.is_race),
}
AutoWorld.call_all(multiworld, "modify_multidata", multidata)
@ -411,7 +348,7 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
output_file_futures.append(pool.submit(write_multidata))
if not check_accessibility_task.result():
if not multiworld.can_beat_game():
raise Exception("Game appears as unbeatable. Aborting.")
raise FillError("Game appears as unbeatable. Aborting.", multiworld=multiworld)
else:
logger.warning("Location Accessibility requirements not fulfilled.")

View File

@ -5,8 +5,15 @@ import multiprocessing
import warnings
if sys.version_info < (3, 8, 6):
raise RuntimeError("Incompatible Python Version. 3.8.7+ is supported.")
if sys.platform in ("win32", "darwin") and sys.version_info < (3, 10, 11):
# Official micro version updates. This should match the number in docs/running from source.md.
raise RuntimeError(f"Incompatible Python Version found: {sys.version_info}. Official 3.10.15+ is supported.")
elif sys.platform in ("win32", "darwin") and sys.version_info < (3, 10, 15):
# There are known security issues, but no easy way to install fixed versions on Windows for testing.
warnings.warn(f"Python Version {sys.version_info} has security issues. Don't use in production.")
elif sys.version_info < (3, 10, 1):
# Other platforms may get security backports instead of micro updates, so the number is unreliable.
raise RuntimeError(f"Incompatible Python Version found: {sys.version_info}. 3.10.1+ is supported.")
# don't run update if environment is frozen/compiled or if not the parent process (skip in subprocess)
_skip_update = bool(getattr(sys, "frozen", False) or multiprocessing.parent_process())
@ -75,13 +82,13 @@ def update(yes: bool = False, force: bool = False) -> None:
if not update_ran:
update_ran = True
install_pkg_resources(yes=yes)
import pkg_resources
if force:
update_command()
return
install_pkg_resources(yes=yes)
import pkg_resources
prev = "" # if a line ends in \ we store here and merge later
for req_file in requirements_files:
path = os.path.join(os.path.dirname(sys.argv[0]), req_file)

View File

@ -15,6 +15,7 @@ import math
import operator
import pickle
import random
import shlex
import threading
import time
import typing
@ -27,9 +28,11 @@ ModuleUpdate.update()
if typing.TYPE_CHECKING:
import ssl
from NetUtils import ServerConnection
import websockets
import colorama
import websockets
from websockets.extensions.permessage_deflate import PerMessageDeflate
try:
# ponyorm is a requirement for webhost, not default server, so may not be importable
from pony.orm.dbapiprovider import OperationalError
@ -40,7 +43,8 @@ import NetUtils
import Utils
from Utils import version_tuple, restricted_loads, Version, async_start, get_intended_text
from NetUtils import Endpoint, ClientStatus, NetworkItem, decode, encode, NetworkPlayer, Permission, NetworkSlot, \
SlotType, LocationStore
SlotType, LocationStore, Hint, HintStatus
from BaseClasses import ItemClassification
min_client_version = Version(0, 1, 6)
colorama.init()
@ -67,6 +71,21 @@ def update_dict(dictionary, entries):
return dictionary
def queue_gc():
import gc
from threading import Thread
gc_thread: typing.Optional[Thread] = getattr(queue_gc, "_thread", None)
def async_collect():
time.sleep(2)
setattr(queue_gc, "_thread", None)
gc.collect()
if not gc_thread:
gc_thread = Thread(target=async_collect)
setattr(queue_gc, "_thread", gc_thread)
gc_thread.start()
# functions callable on storable data on the server by clients
modify_functions = {
# generic:
@ -102,13 +121,14 @@ def get_saving_second(seed_name: str, interval: int = 60) -> int:
class Client(Endpoint):
version = Version(0, 0, 0)
tags: typing.List[str] = []
tags: typing.List[str]
remote_items: bool
remote_start_inventory: bool
no_items: bool
no_locations: bool
no_text: bool
def __init__(self, socket: websockets.WebSocketServerProtocol, ctx: Context):
def __init__(self, socket: "ServerConnection", ctx: Context) -> None:
super().__init__(socket)
self.auth = False
self.team = None
@ -158,6 +178,7 @@ class Context:
"compatibility": int}
# team -> slot id -> list of clients authenticated to slot.
clients: typing.Dict[int, typing.Dict[int, typing.List[Client]]]
endpoints: list[Client]
locations: LocationStore # typing.Dict[int, typing.Dict[int, typing.Tuple[int, int, int]]]
location_checks: typing.Dict[typing.Tuple[int, int], typing.Set[int]]
hints_used: typing.Dict[typing.Tuple[int, int], int]
@ -169,11 +190,9 @@ class Context:
slot_info: typing.Dict[int, NetworkSlot]
generator_version = Version(0, 0, 0)
checksums: typing.Dict[str, str]
item_names: typing.Dict[str, typing.Dict[int, str]] = (
collections.defaultdict(lambda: Utils.KeyedDefaultDict(lambda code: f'Unknown item (ID:{code})')))
item_names: typing.Dict[str, typing.Dict[int, str]]
item_name_groups: typing.Dict[str, typing.Dict[str, typing.Set[str]]]
location_names: typing.Dict[str, typing.Dict[int, str]] = (
collections.defaultdict(lambda: Utils.KeyedDefaultDict(lambda code: f'Unknown location (ID:{code})')))
location_names: typing.Dict[str, typing.Dict[int, str]]
location_name_groups: typing.Dict[str, typing.Dict[str, typing.Set[str]]]
all_item_and_group_names: typing.Dict[str, typing.Set[str]]
all_location_and_group_names: typing.Dict[str, typing.Set[str]]
@ -182,7 +201,6 @@ class Context:
""" each sphere is { player: { location_id, ... } } """
logger: logging.Logger
def __init__(self, host: str, port: int, server_password: str, password: str, location_check_points: int,
hint_cost: int, item_cheat: bool, release_mode: str = "disabled", collect_mode="disabled",
remaining_mode: str = "disabled", auto_shutdown: typing.SupportsFloat = 0, compatibility: int = 2,
@ -215,7 +233,7 @@ class Context:
self.hint_cost = hint_cost
self.location_check_points = location_check_points
self.hints_used = collections.defaultdict(int)
self.hints: typing.Dict[team_slot, typing.Set[NetUtils.Hint]] = collections.defaultdict(set)
self.hints: typing.Dict[team_slot, typing.Set[Hint]] = collections.defaultdict(set)
self.release_mode: str = release_mode
self.remaining_mode: str = remaining_mode
self.collect_mode: str = collect_mode
@ -253,6 +271,10 @@ class Context:
self.location_name_groups = {}
self.all_item_and_group_names = {}
self.all_location_and_group_names = {}
self.item_names = collections.defaultdict(
lambda: Utils.KeyedDefaultDict(lambda code: f'Unknown item (ID:{code})'))
self.location_names = collections.defaultdict(
lambda: Utils.KeyedDefaultDict(lambda code: f'Unknown location (ID:{code})'))
self.non_hintable_names = collections.defaultdict(frozenset)
self._load_game_data()
@ -346,18 +368,28 @@ class Context:
return True
def broadcast_all(self, msgs: typing.List[dict]):
msgs = self.dumper(msgs)
endpoints = (endpoint for endpoint in self.endpoints if endpoint.auth)
async_start(self.broadcast_send_encoded_msgs(endpoints, msgs))
msg_is_text = all(msg["cmd"] == "PrintJSON" for msg in msgs)
data = self.dumper(msgs)
endpoints = (
endpoint
for endpoint in self.endpoints
if endpoint.auth and not (msg_is_text and endpoint.no_text)
)
async_start(self.broadcast_send_encoded_msgs(endpoints, data))
def broadcast_text_all(self, text: str, additional_arguments: dict = {}):
self.logger.info("Notice (all): %s" % text)
self.broadcast_all([{**{"cmd": "PrintJSON", "data": [{ "text": text }]}, **additional_arguments}])
def broadcast_team(self, team: int, msgs: typing.List[dict]):
msgs = self.dumper(msgs)
endpoints = (endpoint for endpoint in itertools.chain.from_iterable(self.clients[team].values()))
async_start(self.broadcast_send_encoded_msgs(endpoints, msgs))
msg_is_text = all(msg["cmd"] == "PrintJSON" for msg in msgs)
data = self.dumper(msgs)
endpoints = (
endpoint
for endpoint in itertools.chain.from_iterable(self.clients[team].values())
if not (msg_is_text and endpoint.no_text)
)
async_start(self.broadcast_send_encoded_msgs(endpoints, data))
def broadcast(self, endpoints: typing.Iterable[Client], msgs: typing.List[dict]):
msgs = self.dumper(msgs)
@ -371,13 +403,13 @@ class Context:
await on_client_disconnected(self, endpoint)
def notify_client(self, client: Client, text: str, additional_arguments: dict = {}):
if not client.auth:
if not client.auth or client.no_text:
return
self.logger.info("Notice (Player %s in team %d): %s" % (client.name, client.team + 1, text))
async_start(self.send_msgs(client, [{"cmd": "PrintJSON", "data": [{ "text": text }], **additional_arguments}]))
def notify_client_multiple(self, client: Client, texts: typing.List[str], additional_arguments: dict = {}):
if not client.auth:
if not client.auth or client.no_text:
return
async_start(self.send_msgs(client,
[{"cmd": "PrintJSON", "data": [{ "text": text }], **additional_arguments}
@ -412,6 +444,8 @@ class Context:
use_embedded_server_options: bool):
self.read_data = {}
# there might be a better place to put this.
self.read_data["race_mode"] = lambda: decoded_obj.get("race_mode", 0)
mdata_ver = decoded_obj["minimum_versions"]["server"]
if mdata_ver > version_tuple:
raise RuntimeError(f"Supplied Multidata (.archipelago) requires a server of at least version {mdata_ver},"
@ -424,7 +458,7 @@ class Context:
self.slot_info = decoded_obj["slot_info"]
self.games = {slot: slot_info.game for slot, slot_info in self.slot_info.items()}
self.groups = {slot: slot_info.group_members for slot, slot_info in self.slot_info.items()
self.groups = {slot: set(slot_info.group_members) for slot, slot_info in self.slot_info.items()
if slot_info.type == SlotType.group}
self.clients = {0: {}}
@ -551,6 +585,9 @@ class Context:
self.logger.info(f"Saving failed. Retry in {self.auto_save_interval} seconds.")
else:
self.save_dirty = False
if not atexit_save: # if atexit is used, that keeps a reference anyway
queue_gc()
self.auto_saver_thread = threading.Thread(target=save_regularly, daemon=True)
self.auto_saver_thread.start()
@ -634,13 +671,29 @@ class Context:
return max(1, int(self.hint_cost * 0.01 * len(self.locations[slot])))
return 0
def recheck_hints(self, team: typing.Optional[int] = None, slot: typing.Optional[int] = None):
def recheck_hints(self, team: typing.Optional[int] = None, slot: typing.Optional[int] = None,
changed: typing.Optional[typing.Set[team_slot]] = None) -> None:
"""Refreshes the hints for the specified team/slot. Providing 'None' for either team or slot
will refresh all teams or all slots respectively. If a set is passed for 'changed', each (team,slot)
pair that has at least one hint modified will be added to the set.
"""
for hint_team, hint_slot in self.hints:
if (team is None or team == hint_team) and (slot is None or slot == hint_slot):
self.hints[hint_team, hint_slot] = {
hint.re_check(self, hint_team) for hint in
self.hints[hint_team, hint_slot]
}
if team != hint_team and team is not None:
continue # Check specified team only, all if team is None
if slot != hint_slot and slot is not None:
continue # Check specified slot only, all if slot is None
new_hints: typing.Set[Hint] = set()
for hint in self.hints[hint_team, hint_slot]:
new_hint = hint.re_check(self, hint_team)
new_hints.add(new_hint)
if hint == new_hint:
continue
for player in self.slot_set(hint.receiving_player) | {hint.finding_player}:
if changed is not None:
changed.add((hint_team,player))
if slot is not None and slot != player:
self.replace_hint(hint_team, player, hint, new_hint)
self.hints[hint_team, hint_slot] = new_hints
def get_rechecked_hints(self, team: int, slot: int):
self.recheck_hints(team, slot)
@ -689,7 +742,7 @@ class Context:
else:
return self.player_names[team, slot]
def notify_hints(self, team: int, hints: typing.List[NetUtils.Hint], only_new: bool = False,
def notify_hints(self, team: int, hints: typing.List[Hint], only_new: bool = False,
recipients: typing.Sequence[int] = None):
"""Send and remember hints."""
if only_new:
@ -704,7 +757,8 @@ class Context:
concerns[player].append(data)
if not hint.local and data not in concerns[hint.finding_player]:
concerns[hint.finding_player].append(data)
# remember hints in all cases
# only remember hints that were not already found at the time of creation
if not hint.found:
# since hints are bidirectional, finding player and receiving player,
# we can check once if hint already exists
@ -720,13 +774,24 @@ class Context:
self.on_new_hint(team, slot)
for slot, hint_data in concerns.items():
if recipients is None or slot in recipients:
clients = self.clients[team].get(slot)
clients = filter(lambda c: not c.no_text, self.clients[team].get(slot, []))
if not clients:
continue
client_hints = [datum[1] for datum in sorted(hint_data, key=lambda x: x[0].finding_player != slot)]
for client in clients:
async_start(self.send_msgs(client, client_hints))
def get_hint(self, team: int, finding_player: int, seeked_location: int) -> typing.Optional[Hint]:
for hint in self.hints[team, finding_player]:
if hint.location == seeked_location:
return hint
return None
def replace_hint(self, team: int, slot: int, old_hint: Hint, new_hint: Hint) -> None:
if old_hint in self.hints[team, slot]:
self.hints[team, slot].remove(old_hint)
self.hints[team, slot].add(new_hint)
# "events"
def on_goal_achieved(self, client: Client):
@ -768,7 +833,7 @@ def update_aliases(ctx: Context, team: int):
async_start(ctx.send_encoded_msgs(client, cmd))
async def server(websocket, path: str = "/", ctx: Context = None):
async def server(websocket: "ServerConnection", path: str = "/", ctx: Context = None) -> None:
client = Client(websocket, ctx)
ctx.endpoints.append(client)
@ -859,6 +924,10 @@ async def on_client_joined(ctx: Context, client: Client):
"If your client supports it, "
"you may have additional local commands you can list with /help.",
{"type": "Tutorial"})
if not any(isinstance(extension, PerMessageDeflate) for extension in client.socket.extensions):
ctx.notify_client(client, "Warning: your client does not support compressed websocket connections! "
"It may stop working in the future. If you are a player, please report this to the "
"client's developer.")
ctx.client_connection_timers[client.team, client.slot] = datetime.datetime.now(datetime.timezone.utc)
@ -925,9 +994,13 @@ def get_status_string(ctx: Context, team: int, tag: str):
tagged = len([client for client in ctx.clients[team][slot] if tag in client.tags])
completion_text = f"({len(ctx.location_checks[team, slot])}/{len(ctx.locations[slot])})"
tag_text = f" {tagged} of which are tagged {tag}" if connected and tag else ""
goal_text = " and has finished." if ctx.client_game_state[team, slot] == ClientStatus.CLIENT_GOAL else "."
status_text = (
" and has finished." if ctx.client_game_state[team, slot] == ClientStatus.CLIENT_GOAL else
" and is ready." if ctx.client_game_state[team, slot] == ClientStatus.CLIENT_READY else
"."
)
text += f"\n{ctx.get_aliased_name(team, slot)} has {connected} connection{'' if connected == 1 else 's'}" \
f"{tag_text}{goal_text} {completion_text}"
f"{tag_text}{status_text} {completion_text}"
return text
@ -991,7 +1064,7 @@ def collect_player(ctx: Context, team: int, slot: int, is_group: bool = False):
collect_player(ctx, team, group, True)
def get_remaining(ctx: Context, team: int, slot: int) -> typing.List[int]:
def get_remaining(ctx: Context, team: int, slot: int) -> typing.List[typing.Tuple[int, int]]:
return ctx.locations.get_remaining(ctx.location_checks, team, slot)
@ -1005,21 +1078,37 @@ def send_items_to(ctx: Context, team: int, target_slot: int, *items: NetworkItem
def register_location_checks(ctx: Context, team: int, slot: int, locations: typing.Iterable[int],
count_activity: bool = True):
slot_locations = ctx.locations[slot]
new_locations = set(locations) - ctx.location_checks[team, slot]
new_locations.intersection_update(ctx.locations[slot]) # ignore location IDs unknown to this multidata
new_locations.intersection_update(slot_locations) # ignore location IDs unknown to this multidata
if new_locations:
if count_activity:
ctx.client_activity_timers[team, slot] = datetime.datetime.now(datetime.timezone.utc)
sortable: list[tuple[int, int, int, int]] = []
for location in new_locations:
item_id, target_player, flags = ctx.locations[slot][location]
# extract all fields to avoid runtime overhead in LocationStore
item_id, target_player, flags = slot_locations[location]
# sort/group by receiver and item
sortable.append((target_player, item_id, location, flags))
info_texts: list[dict[str, typing.Any]] = []
for target_player, item_id, location, flags in sorted(sortable):
new_item = NetworkItem(item_id, location, slot, flags)
send_items_to(ctx, team, target_player, new_item)
ctx.logger.info('(Team #%d) %s sent %s to %s (%s)' % (
team + 1, ctx.player_names[(team, slot)], ctx.item_names[ctx.slot_info[target_player].game][item_id],
ctx.player_names[(team, target_player)], ctx.location_names[ctx.slot_info[slot].game][location]))
info_text = json_format_send_event(new_item, target_player)
ctx.broadcast_team(team, [info_text])
if len(info_texts) >= 140:
# split into chunks that are close to compression window of 64K but not too big on the wire
# (roughly 1300-2600 bytes after compression depending on repetitiveness)
ctx.broadcast_team(team, info_texts)
info_texts.clear()
info_texts.append(json_format_send_event(new_item, target_player))
ctx.broadcast_team(team, info_texts)
del info_texts
del sortable
ctx.location_checks[team, slot] |= new_locations
send_new_items(ctx)
@ -1028,14 +1117,15 @@ def register_location_checks(ctx: Context, team: int, slot: int, locations: typi
"hint_points": get_slot_points(ctx, team, slot),
"checked_locations": new_locations, # send back new checks only
}])
old_hints = ctx.hints[team, slot].copy()
ctx.recheck_hints(team, slot)
if old_hints != ctx.hints[team, slot]:
ctx.on_changed_hints(team, slot)
updated_slots: typing.Set[tuple[int, int]] = set()
ctx.recheck_hints(team, slot, updated_slots)
for hint_team, hint_slot in updated_slots:
ctx.on_changed_hints(hint_team, hint_slot)
ctx.save()
def collect_hints(ctx: Context, team: int, slot: int, item: typing.Union[int, str]) -> typing.List[NetUtils.Hint]:
def collect_hints(ctx: Context, team: int, slot: int, item: typing.Union[int, str], auto_status: HintStatus) \
-> typing.List[Hint]:
hints = []
slots: typing.Set[int] = {slot}
for group_id, group in ctx.groups.items():
@ -1045,31 +1135,58 @@ def collect_hints(ctx: Context, team: int, slot: int, item: typing.Union[int, st
seeked_item_id = item if isinstance(item, int) else ctx.item_names_for_game(ctx.games[slot])[item]
for finding_player, location_id, item_id, receiving_player, item_flags \
in ctx.locations.find_item(slots, seeked_item_id):
found = location_id in ctx.location_checks[team, finding_player]
entrance = ctx.er_hint_data.get(finding_player, {}).get(location_id, "")
hints.append(NetUtils.Hint(receiving_player, finding_player, location_id, item_id, found, entrance,
item_flags))
prev_hint = ctx.get_hint(team, slot, location_id)
if prev_hint:
hints.append(prev_hint)
else:
found = location_id in ctx.location_checks[team, finding_player]
entrance = ctx.er_hint_data.get(finding_player, {}).get(location_id, "")
new_status = auto_status
if found:
new_status = HintStatus.HINT_FOUND
elif item_flags & ItemClassification.trap:
new_status = HintStatus.HINT_AVOID
hints.append(Hint(receiving_player, finding_player, location_id, item_id, found, entrance,
item_flags, new_status))
return hints
def collect_hint_location_name(ctx: Context, team: int, slot: int, location: str) -> typing.List[NetUtils.Hint]:
def collect_hint_location_name(ctx: Context, team: int, slot: int, location: str, auto_status: HintStatus) \
-> typing.List[Hint]:
seeked_location: int = ctx.location_names_for_game(ctx.games[slot])[location]
return collect_hint_location_id(ctx, team, slot, seeked_location)
return collect_hint_location_id(ctx, team, slot, seeked_location, auto_status)
def collect_hint_location_id(ctx: Context, team: int, slot: int, seeked_location: int) -> typing.List[NetUtils.Hint]:
def collect_hint_location_id(ctx: Context, team: int, slot: int, seeked_location: int, auto_status: HintStatus) \
-> typing.List[Hint]:
prev_hint = ctx.get_hint(team, slot, seeked_location)
if prev_hint:
return [prev_hint]
result = ctx.locations[slot].get(seeked_location, (None, None, None))
if any(result):
item_id, receiving_player, item_flags = result
found = seeked_location in ctx.location_checks[team, slot]
entrance = ctx.er_hint_data.get(slot, {}).get(seeked_location, "")
return [NetUtils.Hint(receiving_player, slot, seeked_location, item_id, found, entrance, item_flags)]
new_status = auto_status
if found:
new_status = HintStatus.HINT_FOUND
elif item_flags & ItemClassification.trap:
new_status = HintStatus.HINT_AVOID
return [Hint(receiving_player, slot, seeked_location, item_id, found, entrance, item_flags,
new_status)]
return []
def format_hint(ctx: Context, team: int, hint: NetUtils.Hint) -> str:
status_names: typing.Dict[HintStatus, str] = {
HintStatus.HINT_FOUND: "(found)",
HintStatus.HINT_UNSPECIFIED: "(unspecified)",
HintStatus.HINT_NO_PRIORITY: "(no priority)",
HintStatus.HINT_AVOID: "(avoid)",
HintStatus.HINT_PRIORITY: "(priority)",
}
def format_hint(ctx: Context, team: int, hint: Hint) -> str:
text = f"[Hint]: {ctx.player_names[team, hint.receiving_player]}'s " \
f"{ctx.item_names[ctx.slot_info[hint.receiving_player].game][hint.item]} is " \
f"at {ctx.location_names[ctx.slot_info[hint.finding_player].game][hint.location]} " \
@ -1077,7 +1194,8 @@ def format_hint(ctx: Context, team: int, hint: NetUtils.Hint) -> str:
if hint.entrance:
text += f" at {hint.entrance}"
return text + (". (found)" if hint.found else ".")
return text + ". " + status_names.get(hint.status, "(unknown)")
def json_format_send_event(net_item: NetworkItem, receiving_player: int):
@ -1132,7 +1250,10 @@ class CommandProcessor(metaclass=CommandMeta):
if not raw:
return
try:
command = raw.split()
try:
command = shlex.split(raw, comments=False)
except ValueError: # most likely: "ValueError: No closing quotation"
command = raw.split()
basecommand = command[0]
if basecommand[0] == self.marker:
method = self.commands.get(basecommand[1:].lower(), None)
@ -1203,6 +1324,10 @@ class CommonCommandProcessor(CommandProcessor):
timer = int(seconds, 10)
except ValueError:
timer = 10
else:
if timer > 60 * 60:
raise ValueError(f"{timer} is invalid. Maximum is 1 hour.")
async_start(countdown(self.ctx, timer))
return True
@ -1350,10 +1475,10 @@ class ClientMessageProcessor(CommonCommandProcessor):
def _cmd_remaining(self) -> bool:
"""List remaining items in your game, but not their location or recipient"""
if self.ctx.remaining_mode == "enabled":
remaining_item_ids = get_remaining(self.ctx, self.client.team, self.client.slot)
if remaining_item_ids:
self.output("Remaining items: " + ", ".join(self.ctx.item_names[self.client.slot.game][item_id]
for item_id in remaining_item_ids))
rest_locations = get_remaining(self.ctx, self.client.team, self.client.slot)
if rest_locations:
self.output("Remaining items: " + ", ".join(self.ctx.item_names[self.ctx.games[slot]][item_id]
for slot, item_id in rest_locations))
else:
self.output("No remaining items found.")
return True
@ -1363,10 +1488,10 @@ class ClientMessageProcessor(CommonCommandProcessor):
return False
else: # is goal
if self.ctx.client_game_state[self.client.team, self.client.slot] == ClientStatus.CLIENT_GOAL:
remaining_item_ids = get_remaining(self.ctx, self.client.team, self.client.slot)
if remaining_item_ids:
self.output("Remaining items: " + ", ".join(self.ctx.item_names[self.client.slot.game][item_id]
for item_id in remaining_item_ids))
rest_locations = get_remaining(self.ctx, self.client.team, self.client.slot)
if rest_locations:
self.output("Remaining items: " + ", ".join(self.ctx.item_names[self.ctx.games[slot]][item_id]
for slot, item_id in rest_locations))
else:
self.output("No remaining items found.")
return True
@ -1474,7 +1599,7 @@ class ClientMessageProcessor(CommonCommandProcessor):
def get_hints(self, input_text: str, for_location: bool = False) -> bool:
points_available = get_client_points(self.ctx, self.client)
cost = self.ctx.get_hint_cost(self.client.slot)
auto_status = HintStatus.HINT_UNSPECIFIED if for_location else HintStatus.HINT_PRIORITY
if not input_text:
hints = {hint.re_check(self.ctx, self.client.team) for hint in
self.ctx.hints[self.client.team, self.client.slot]}
@ -1500,9 +1625,9 @@ class ClientMessageProcessor(CommonCommandProcessor):
self.output(f"Sorry, \"{hint_name}\" is marked as non-hintable.")
hints = []
elif not for_location:
hints = collect_hints(self.ctx, self.client.team, self.client.slot, hint_id)
hints = collect_hints(self.ctx, self.client.team, self.client.slot, hint_id, auto_status)
else:
hints = collect_hint_location_id(self.ctx, self.client.team, self.client.slot, hint_id)
hints = collect_hint_location_id(self.ctx, self.client.team, self.client.slot, hint_id, auto_status)
else:
game = self.ctx.games[self.client.slot]
@ -1522,16 +1647,16 @@ class ClientMessageProcessor(CommonCommandProcessor):
hints = []
for item_name in self.ctx.item_name_groups[game][hint_name]:
if item_name in self.ctx.item_names_for_game(game): # ensure item has an ID
hints.extend(collect_hints(self.ctx, self.client.team, self.client.slot, item_name))
hints.extend(collect_hints(self.ctx, self.client.team, self.client.slot, item_name, auto_status))
elif not for_location and hint_name in self.ctx.item_names_for_game(game): # item name
hints = collect_hints(self.ctx, self.client.team, self.client.slot, hint_name)
hints = collect_hints(self.ctx, self.client.team, self.client.slot, hint_name, auto_status)
elif hint_name in self.ctx.location_name_groups[game]: # location group name
hints = []
for loc_name in self.ctx.location_name_groups[game][hint_name]:
if loc_name in self.ctx.location_names_for_game(game):
hints.extend(collect_hint_location_name(self.ctx, self.client.team, self.client.slot, loc_name))
hints.extend(collect_hint_location_name(self.ctx, self.client.team, self.client.slot, loc_name, auto_status))
else: # location name
hints = collect_hint_location_name(self.ctx, self.client.team, self.client.slot, hint_name)
hints = collect_hint_location_name(self.ctx, self.client.team, self.client.slot, hint_name, auto_status)
else:
self.output(response)
@ -1696,7 +1821,9 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict):
ctx.clients[team][slot].append(client)
client.version = args['version']
client.tags = args['tags']
client.no_locations = 'TextOnly' in client.tags or 'Tracker' in client.tags
client.no_locations = "TextOnly" in client.tags or "Tracker" in client.tags
# set NoText for old PopTracker clients that predate the tag to save traffic
client.no_text = "NoText" in client.tags or ("PopTracker" in client.tags and client.version < (0, 5, 1))
connected_packet = {
"cmd": "Connected",
"team": client.team, "slot": client.slot,
@ -1769,6 +1896,9 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict):
client.tags = args["tags"]
if set(old_tags) != set(client.tags):
client.no_locations = 'TextOnly' in client.tags or 'Tracker' in client.tags
client.no_text = "NoText" in client.tags or (
"PopTracker" in client.tags and client.version < (0, 5, 1)
)
ctx.broadcast_text_all(
f"{ctx.get_aliased_name(client.team, client.slot)} (Team #{client.team + 1}) has changed tags "
f"from {old_tags} to {client.tags}.",
@ -1797,19 +1927,63 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict):
for location in args["locations"]:
if type(location) is not int:
await ctx.send_msgs(client,
[{'cmd': 'InvalidPacket', "type": "arguments", "text": 'LocationScouts',
[{'cmd': 'InvalidPacket', "type": "arguments",
"text": 'Locations has to be a list of integers',
"original_cmd": cmd}])
return
target_item, target_player, flags = ctx.locations[client.slot][location]
if create_as_hint:
hints.extend(collect_hint_location_id(ctx, client.team, client.slot, location))
hints.extend(collect_hint_location_id(ctx, client.team, client.slot, location,
HintStatus.HINT_UNSPECIFIED))
locs.append(NetworkItem(target_item, location, target_player, flags))
ctx.notify_hints(client.team, hints, only_new=create_as_hint == 2)
if locs and create_as_hint:
ctx.save()
await ctx.send_msgs(client, [{'cmd': 'LocationInfo', 'locations': locs}])
elif cmd == 'UpdateHint':
location = args["location"]
player = args["player"]
status = args["status"]
if not isinstance(player, int) or not isinstance(location, int) \
or (status is not None and not isinstance(status, int)):
await ctx.send_msgs(client,
[{'cmd': 'InvalidPacket', "type": "arguments", "text": 'UpdateHint',
"original_cmd": cmd}])
return
hint = ctx.get_hint(client.team, player, location)
if not hint:
return # Ignored safely
if client.slot not in ctx.slot_set(hint.receiving_player):
await ctx.send_msgs(client,
[{'cmd': 'InvalidPacket', "type": "arguments", "text": 'UpdateHint: No Permission',
"original_cmd": cmd}])
return
new_hint = hint
if status is None:
return
try:
status = HintStatus(status)
except ValueError:
await ctx.send_msgs(client,
[{'cmd': 'InvalidPacket', "type": "arguments",
"text": 'UpdateHint: Invalid Status', "original_cmd": cmd}])
return
if status == HintStatus.HINT_FOUND:
await ctx.send_msgs(client,
[{'cmd': 'InvalidPacket', "type": "arguments",
"text": 'UpdateHint: Cannot manually update status to "HINT_FOUND"', "original_cmd": cmd}])
return
new_hint = new_hint.re_prioritize(ctx, status)
if hint == new_hint:
return
ctx.replace_hint(client.team, hint.finding_player, hint, new_hint)
ctx.replace_hint(client.team, hint.receiving_player, hint, new_hint)
ctx.save()
ctx.on_changed_hints(client.team, hint.finding_player)
ctx.on_changed_hints(client.team, hint.receiving_player)
elif cmd == 'StatusUpdate':
update_client_status(ctx, client, args["status"])
@ -1857,6 +2031,7 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict):
args["cmd"] = "SetReply"
value = ctx.stored_data.get(args["key"], args.get("default", 0))
args["original_value"] = copy.copy(value)
args["slot"] = client.slot
for operation in args["operations"]:
func = modify_functions[operation["operation"]]
value = func(value, operation["value"])
@ -1931,8 +2106,10 @@ class ServerCommandProcessor(CommonCommandProcessor):
def _cmd_exit(self) -> bool:
"""Shutdown the server"""
self.ctx.server.ws_server.close()
self.ctx.exit_event.set()
try:
self.ctx.server.ws_server.close()
finally:
self.ctx.exit_event.set()
return True
@mark_raw
@ -2039,6 +2216,8 @@ class ServerCommandProcessor(CommonCommandProcessor):
item_name, usable, response = get_intended_text(item_name, names)
if usable:
amount: int = int(amount)
if amount > 100:
raise ValueError(f"{amount} is invalid. Maximum is 100.")
new_items = [NetworkItem(names[item_name], -1, 0) for _ in range(int(amount))]
send_items_to(self.ctx, team, slot, *new_items)
@ -2110,9 +2289,9 @@ class ServerCommandProcessor(CommonCommandProcessor):
hints = []
for item_name_from_group in self.ctx.item_name_groups[game][item]:
if item_name_from_group in self.ctx.item_names_for_game(game): # ensure item has an ID
hints.extend(collect_hints(self.ctx, team, slot, item_name_from_group))
hints.extend(collect_hints(self.ctx, team, slot, item_name_from_group, HintStatus.HINT_PRIORITY))
else: # item name or id
hints = collect_hints(self.ctx, team, slot, item)
hints = collect_hints(self.ctx, team, slot, item, HintStatus.HINT_PRIORITY)
if hints:
self.ctx.notify_hints(team, hints)
@ -2146,14 +2325,17 @@ class ServerCommandProcessor(CommonCommandProcessor):
if usable:
if isinstance(location, int):
hints = collect_hint_location_id(self.ctx, team, slot, location)
hints = collect_hint_location_id(self.ctx, team, slot, location,
HintStatus.HINT_UNSPECIFIED)
elif game in self.ctx.location_name_groups and location in self.ctx.location_name_groups[game]:
hints = []
for loc_name_from_group in self.ctx.location_name_groups[game][location]:
if loc_name_from_group in self.ctx.location_names_for_game(game):
hints.extend(collect_hint_location_name(self.ctx, team, slot, loc_name_from_group))
hints.extend(collect_hint_location_name(self.ctx, team, slot, loc_name_from_group,
HintStatus.HINT_UNSPECIFIED))
else:
hints = collect_hint_location_name(self.ctx, team, slot, location)
hints = collect_hint_location_name(self.ctx, team, slot, location,
HintStatus.HINT_UNSPECIFIED)
if hints:
self.ctx.notify_hints(team, hints)
else:
@ -2243,6 +2425,8 @@ def parse_args() -> argparse.Namespace:
parser.add_argument('--cert_key', help="Path to SSL Certificate Key file")
parser.add_argument('--loglevel', default=defaults["loglevel"],
choices=['debug', 'info', 'warning', 'error', 'critical'])
parser.add_argument('--logtime', help="Add timestamps to STDOUT",
default=defaults["logtime"], action='store_true')
parser.add_argument('--location_check_points', default=defaults["location_check_points"], type=int)
parser.add_argument('--hint_cost', default=defaults["hint_cost"], type=int)
parser.add_argument('--disable_item_cheat', default=defaults["disable_item_cheat"], action='store_true')
@ -2323,7 +2507,9 @@ def load_server_cert(path: str, cert_key: typing.Optional[str]) -> "ssl.SSLConte
async def main(args: argparse.Namespace):
Utils.init_logging("Server", loglevel=args.loglevel.lower())
Utils.init_logging(name="Server",
loglevel=args.loglevel.lower(),
add_timestamp=args.logtime)
ctx = Context(args.host, args.port, args.server_password, args.password, args.location_check_points,
args.hint_cost, not args.disable_item_cheat, args.release_mode, args.collect_mode,

View File

@ -5,11 +5,20 @@ import enum
import warnings
from json import JSONEncoder, JSONDecoder
import websockets
if typing.TYPE_CHECKING:
from websockets import WebSocketServerProtocol as ServerConnection
from Utils import ByValue, Version
class HintStatus(ByValue, enum.IntEnum):
HINT_FOUND = 0
HINT_UNSPECIFIED = 1
HINT_NO_PRIORITY = 10
HINT_AVOID = 20
HINT_PRIORITY = 30
class JSONMessagePart(typing.TypedDict, total=False):
text: str
# optional
@ -19,6 +28,8 @@ class JSONMessagePart(typing.TypedDict, total=False):
player: int
# if type == item indicates item flags
flags: int
# if type == hint_status
hint_status: HintStatus
class ClientStatus(ByValue, enum.IntEnum):
@ -79,6 +90,7 @@ class NetworkItem(typing.NamedTuple):
item: int
location: int
player: int
""" Sending player, except in LocationInfo (from LocationScouts), where it is the receiving player. """
flags: int = 0
@ -140,7 +152,7 @@ decode = JSONDecoder(object_hook=_object_hook).decode
class Endpoint:
socket: websockets.WebSocketServerProtocol
socket: "ServerConnection"
def __init__(self, socket):
self.socket = socket
@ -183,6 +195,7 @@ class JSONTypes(str, enum.Enum):
location_name = "location_name"
location_id = "location_id"
entrance_name = "entrance_name"
hint_status = "hint_status"
class JSONtoTextParser(metaclass=HandlerMeta):
@ -223,7 +236,7 @@ class JSONtoTextParser(metaclass=HandlerMeta):
def _handle_player_id(self, node: JSONMessagePart):
player = int(node["text"])
node["color"] = 'magenta' if player == self.ctx.slot else 'yellow'
node["color"] = 'magenta' if self.ctx.slot_concerns_self(player) else 'yellow'
node["text"] = self.ctx.player_names[player]
return self._handle_color(node)
@ -264,6 +277,10 @@ class JSONtoTextParser(metaclass=HandlerMeta):
node["color"] = 'blue'
return self._handle_color(node)
def _handle_hint_status(self, node: JSONMessagePart):
node["color"] = status_colors.get(node["hint_status"], "red")
return self._handle_color(node)
class RawJSONtoTextParser(JSONtoTextParser):
def _handle_color(self, node: JSONMessagePart):
@ -272,7 +289,8 @@ class RawJSONtoTextParser(JSONtoTextParser):
color_codes = {'reset': 0, 'bold': 1, 'underline': 4, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33, 'blue': 34,
'magenta': 35, 'cyan': 36, 'white': 37, 'black_bg': 40, 'red_bg': 41, 'green_bg': 42, 'yellow_bg': 43,
'blue_bg': 44, 'magenta_bg': 45, 'cyan_bg': 46, 'white_bg': 47}
'blue_bg': 44, 'magenta_bg': 45, 'cyan_bg': 46, 'white_bg': 47,
'plum': 35, 'slateblue': 34, 'salmon': 31,} # convert ui colors to terminal colors
def color_code(*args):
@ -295,6 +313,27 @@ def add_json_location(parts: list, location_id: int, player: int = 0, **kwargs)
parts.append({"text": str(location_id), "player": player, "type": JSONTypes.location_id, **kwargs})
status_names: typing.Dict[HintStatus, str] = {
HintStatus.HINT_FOUND: "(found)",
HintStatus.HINT_UNSPECIFIED: "(unspecified)",
HintStatus.HINT_NO_PRIORITY: "(no priority)",
HintStatus.HINT_AVOID: "(avoid)",
HintStatus.HINT_PRIORITY: "(priority)",
}
status_colors: typing.Dict[HintStatus, str] = {
HintStatus.HINT_FOUND: "green",
HintStatus.HINT_UNSPECIFIED: "white",
HintStatus.HINT_NO_PRIORITY: "slateblue",
HintStatus.HINT_AVOID: "salmon",
HintStatus.HINT_PRIORITY: "plum",
}
def add_json_hint_status(parts: list, hint_status: HintStatus, text: typing.Optional[str] = None, **kwargs):
parts.append({"text": text if text != None else status_names.get(hint_status, "(unknown)"),
"hint_status": hint_status, "type": JSONTypes.hint_status, **kwargs})
class Hint(typing.NamedTuple):
receiving_player: int
finding_player: int
@ -303,14 +342,21 @@ class Hint(typing.NamedTuple):
found: bool
entrance: str = ""
item_flags: int = 0
status: HintStatus = HintStatus.HINT_UNSPECIFIED
def re_check(self, ctx, team) -> Hint:
if self.found:
if self.found and self.status == HintStatus.HINT_FOUND:
return self
found = self.location in ctx.location_checks[team, self.finding_player]
if found:
return Hint(self.receiving_player, self.finding_player, self.location, self.item, found, self.entrance,
self.item_flags)
return self._replace(found=found, status=HintStatus.HINT_FOUND)
return self
def re_prioritize(self, ctx, status: HintStatus) -> Hint:
if self.found and status != HintStatus.HINT_FOUND:
status = HintStatus.HINT_FOUND
if status != self.status:
return self._replace(status=status)
return self
def __hash__(self):
@ -332,10 +378,7 @@ class Hint(typing.NamedTuple):
else:
add_json_text(parts, "'s World")
add_json_text(parts, ". ")
if self.found:
add_json_text(parts, "(found)", type="color", color="green")
else:
add_json_text(parts, "(not found)", type="color", color="red")
add_json_hint_status(parts, self.status)
return {"cmd": "PrintJSON", "data": parts, "type": "Hint",
"receiving": self.receiving_player,
@ -381,6 +424,8 @@ class _LocationStore(dict, typing.MutableMapping[int, typing.Dict[int, typing.Tu
checked = state[team, slot]
if not checked:
# This optimizes the case where everyone connects to a fresh game at the same time.
if slot not in self:
raise KeyError(slot)
return []
return [location_id for
location_id in self[slot] if
@ -397,12 +442,12 @@ class _LocationStore(dict, typing.MutableMapping[int, typing.Dict[int, typing.Tu
location_id not in checked]
def get_remaining(self, state: typing.Dict[typing.Tuple[int, int], typing.Set[int]], team: int, slot: int
) -> typing.List[int]:
) -> typing.List[typing.Tuple[int, int]]:
checked = state[team, slot]
player_locations = self[slot]
return sorted([player_locations[location_id][0] for
location_id in player_locations if
location_id not in checked])
return sorted([(player_locations[location_id][1], player_locations[location_id][0]) for
location_id in player_locations if
location_id not in checked])
if typing.TYPE_CHECKING: # type-check with pure python implementation until we have a typing stub

View File

@ -1,7 +1,6 @@
import tkinter as tk
import argparse
import logging
import random
import os
import zipfile
from itertools import chain
@ -197,7 +196,6 @@ def set_icon(window):
def adjust(args):
# Create a fake multiworld and OOTWorld to use as a base
multiworld = MultiWorld(1)
multiworld.per_slot_randoms = {1: random}
ootworld = OOTWorld(multiworld, 1)
# Set options in the fake OOTWorld
for name, option in chain(cosmetic_options.items(), sfx_options.items()):

View File

@ -8,16 +8,17 @@ import numbers
import random
import typing
import enum
from collections import defaultdict
from copy import deepcopy
from dataclasses import dataclass
from schema import And, Optional, Or, Schema
from typing_extensions import Self
from Utils import get_fuzzy_results, is_iterable_except_str
from Utils import get_file_safe_name, get_fuzzy_results, is_iterable_except_str, output_path
if typing.TYPE_CHECKING:
from BaseClasses import PlandoOptions
from BaseClasses import MultiWorld, PlandoOptions
from worlds.AutoWorld import World
import pathlib
@ -53,8 +54,8 @@ class AssembleOptions(abc.ABCMeta):
attrs["name_lookup"].update({option_id: name for name, option_id in new_options.items()})
options.update(new_options)
# apply aliases, without name_lookup
aliases = {name[6:].lower(): option_id for name, option_id in attrs.items() if
name.startswith("alias_")}
aliases = attrs["aliases"] = {name[6:].lower(): option_id for name, option_id in attrs.items() if
name.startswith("alias_")}
assert (
name in {"Option", "VerifyKeys"} or # base abstract classes don't need default
@ -126,10 +127,28 @@ class Option(typing.Generic[T], metaclass=AssembleOptions):
# can be weighted between selections
supports_weighting = True
rich_text_doc: typing.Optional[bool] = None
"""Whether the WebHost should render the Option's docstring as rich text.
If this is True, the Option's docstring is interpreted as reStructuredText_,
the standard Python markup format. In the WebHost, it's rendered to HTML so
that lists, emphasis, and other rich text features are displayed properly.
If this is False, the docstring is instead interpreted as plain text, and
displayed as-is on the WebHost with whitespace preserved.
If this is None, it inherits the value of `WebWorld.rich_text_options_doc`. For
backwards compatibility, this defaults to False, but worlds are encouraged to
set it to True and use reStructuredText for their Option documentation.
.. _reStructuredText: https://docutils.sourceforge.io/rst.html
"""
# filled by AssembleOptions:
name_lookup: typing.ClassVar[typing.Dict[T, str]] # type: ignore
# https://github.com/python/typing/discussions/1460 the reason for this type: ignore
options: typing.ClassVar[typing.Dict[str, int]]
aliases: typing.ClassVar[typing.Dict[str, int]]
def __repr__(self) -> str:
return f"{self.__class__.__name__}({self.current_option_name})"
@ -477,7 +496,7 @@ class TextChoice(Choice):
def __init__(self, value: typing.Union[str, int]):
assert isinstance(value, str) or isinstance(value, int), \
f"{value} is not a valid option for {self.__class__.__name__}"
f"'{value}' is not a valid option for '{self.__class__.__name__}'"
self.value = value
@property
@ -598,17 +617,17 @@ class PlandoBosses(TextChoice, metaclass=BossMeta):
used_locations.append(location)
used_bosses.append(boss)
if not cls.valid_boss_name(boss):
raise ValueError(f"{boss.title()} is not a valid boss name.")
raise ValueError(f"'{boss.title()}' is not a valid boss name.")
if not cls.valid_location_name(location):
raise ValueError(f"{location.title()} is not a valid boss location name.")
raise ValueError(f"'{location.title()}' is not a valid boss location name.")
if not cls.can_place_boss(boss, location):
raise ValueError(f"{location.title()} is not a valid location for {boss.title()} to be placed.")
raise ValueError(f"'{location.title()}' is not a valid location for {boss.title()} to be placed.")
else:
if cls.duplicate_bosses:
if not cls.valid_boss_name(option):
raise ValueError(f"{option} is not a valid boss name.")
raise ValueError(f"'{option}' is not a valid boss name.")
else:
raise ValueError(f"{option.title()} is not formatted correctly.")
raise ValueError(f"'{option.title()}' is not formatted correctly.")
@classmethod
def can_place_boss(cls, boss: str, location: str) -> bool:
@ -670,9 +689,9 @@ class Range(NumericOption):
@classmethod
def weighted_range(cls, text) -> Range:
if text == "random-low":
return cls(cls.triangular(cls.range_start, cls.range_end, cls.range_start))
return cls(cls.triangular(cls.range_start, cls.range_end, 0.0))
elif text == "random-high":
return cls(cls.triangular(cls.range_start, cls.range_end, cls.range_end))
return cls(cls.triangular(cls.range_start, cls.range_end, 1.0))
elif text == "random-middle":
return cls(cls.triangular(cls.range_start, cls.range_end))
elif text.startswith("random-range-"):
@ -698,11 +717,11 @@ class Range(NumericOption):
f"{random_range[0]}-{random_range[1]} is outside allowed range "
f"{cls.range_start}-{cls.range_end} for option {cls.__name__}")
if text.startswith("random-range-low"):
return cls(cls.triangular(random_range[0], random_range[1], random_range[0]))
return cls(cls.triangular(random_range[0], random_range[1], 0.0))
elif text.startswith("random-range-middle"):
return cls(cls.triangular(random_range[0], random_range[1]))
elif text.startswith("random-range-high"):
return cls(cls.triangular(random_range[0], random_range[1], random_range[1]))
return cls(cls.triangular(random_range[0], random_range[1], 1.0))
else:
return cls(random.randint(random_range[0], random_range[1]))
@ -720,8 +739,16 @@ class Range(NumericOption):
return str(self.value)
@staticmethod
def triangular(lower: int, end: int, tri: typing.Optional[int] = None) -> int:
return int(round(random.triangular(lower, end, tri), 0))
def triangular(lower: int, end: int, tri: float = 0.5) -> int:
"""
Integer triangular distribution for `lower` inclusive to `end` inclusive.
Expects `lower <= end` and `0.0 <= tri <= 1.0`. The result of other inputs is undefined.
"""
# Use the continuous range [lower, end + 1) to produce an integer result in [lower, end].
# random.triangular is actually [a, b] and not [a, b), so there is a very small chance of getting exactly b even
# when a != b, so ensure the result is never more than `end`.
return min(end, math.floor(random.triangular(0.0, 1.0, tri) * (end - lower + 1) + lower))
class NamedRange(Range):
@ -735,6 +762,12 @@ class NamedRange(Range):
elif value > self.range_end and value not in self.special_range_names.values():
raise Exception(f"{value} is higher than maximum {self.range_end} for option {self.__class__.__name__} " +
f"and is also not one of the supported named special values: {self.special_range_names}")
# See docstring
for key in self.special_range_names:
if key != key.lower():
raise Exception(f"{self.__class__.__name__} has an invalid special_range_names key: {key}. "
f"NamedRange keys must use only lowercase letters, and ideally should be snake_case.")
self.value = value
@classmethod
@ -762,17 +795,22 @@ class VerifyKeys(metaclass=FreezeValidKeys):
verify_location_name: bool = False
value: typing.Any
@classmethod
def verify_keys(cls, data: typing.Iterable[str]) -> None:
if cls.valid_keys:
data = set(data)
dataset = set(word.casefold() for word in data) if cls.valid_keys_casefold else set(data)
extra = dataset - cls._valid_keys
def verify_keys(self) -> None:
if self.valid_keys:
data = set(self.value)
dataset = set(word.casefold() for word in data) if self.valid_keys_casefold else set(data)
extra = dataset - self._valid_keys
if extra:
raise Exception(f"Found unexpected key {', '.join(extra)} in {cls}. "
f"Allowed keys: {cls._valid_keys}.")
raise OptionError(
f"Found unexpected key {', '.join(extra)} in {getattr(self, 'display_name', self)}. "
f"Allowed keys: {self._valid_keys}."
)
def verify(self, world: typing.Type[World], player_name: str, plando_options: "PlandoOptions") -> None:
try:
self.verify_keys()
except OptionError as validation_error:
raise OptionError(f"Player {player_name} has invalid option keys:\n{validation_error}")
if self.convert_name_groups and self.verify_item_name:
new_value = type(self.value)() # empty container of whatever value is
for item_name in self.value:
@ -787,18 +825,21 @@ class VerifyKeys(metaclass=FreezeValidKeys):
for item_name in self.value:
if item_name not in world.item_names:
picks = get_fuzzy_results(item_name, world.item_names, limit=1)
raise Exception(f"Item {item_name} from option {self} "
f"is not a valid item name from {world.game}. "
raise Exception(f"Item '{item_name}' from option '{self}' "
f"is not a valid item name from '{world.game}'. "
f"Did you mean '{picks[0][0]}' ({picks[0][1]}% sure)")
elif self.verify_location_name:
for location_name in self.value:
if location_name not in world.location_names:
picks = get_fuzzy_results(location_name, world.location_names, limit=1)
raise Exception(f"Location {location_name} from option {self} "
f"is not a valid location name from {world.game}. "
raise Exception(f"Location '{location_name}' from option '{self}' "
f"is not a valid location name from '{world.game}'. "
f"Did you mean '{picks[0][0]}' ({picks[0][1]}% sure)")
def __iter__(self) -> typing.Iterator[typing.Any]:
return self.value.__iter__()
class OptionDict(Option[typing.Dict[str, typing.Any]], VerifyKeys, typing.Mapping[str, typing.Any]):
default = {}
supports_weighting = False
@ -809,7 +850,6 @@ class OptionDict(Option[typing.Dict[str, typing.Any]], VerifyKeys, typing.Mappin
@classmethod
def from_any(cls, data: typing.Dict[str, typing.Any]) -> OptionDict:
if type(data) == dict:
cls.verify_keys(data)
return cls(data)
else:
raise NotImplementedError(f"Cannot Convert from non-dictionary, got {type(data)}")
@ -831,6 +871,8 @@ class ItemDict(OptionDict):
verify_item_name = True
def __init__(self, value: typing.Dict[str, int]):
if any(item_count is None for item_count in value.values()):
raise Exception("Items must have counts associated with them. Please provide positive integer values in the format \"item\": count .")
if any(item_count < 1 for item_count in value.values()):
raise Exception("Cannot have non-positive item counts.")
super(ItemDict, self).__init__(value)
@ -855,7 +897,6 @@ class OptionList(Option[typing.List[typing.Any]], VerifyKeys):
@classmethod
def from_any(cls, data: typing.Any):
if is_iterable_except_str(data):
cls.verify_keys(data)
return cls(data)
return cls.from_text(str(data))
@ -881,7 +922,6 @@ class OptionSet(Option[typing.Set[str]], VerifyKeys):
@classmethod
def from_any(cls, data: typing.Any):
if is_iterable_except_str(data):
cls.verify_keys(data)
return cls(data)
return cls.from_text(str(data))
@ -924,6 +964,19 @@ class PlandoTexts(Option[typing.List[PlandoText]], VerifyKeys):
self.value = []
logging.warning(f"The plando texts module is turned off, "
f"so text for {player_name} will be ignored.")
else:
super().verify(world, player_name, plando_options)
def verify_keys(self) -> None:
if self.valid_keys:
data = set(text.at for text in self)
dataset = set(word.casefold() for word in data) if self.valid_keys_casefold else set(data)
extra = dataset - self._valid_keys
if extra:
raise OptionError(
f"Invalid \"at\" placement {', '.join(extra)} in {getattr(self, 'display_name', self)}. "
f"Allowed placements: {self._valid_keys}."
)
@classmethod
def from_any(cls, data: PlandoTextsFromAnyType) -> Self:
@ -934,7 +987,19 @@ class PlandoTexts(Option[typing.List[PlandoText]], VerifyKeys):
if random.random() < float(text.get("percentage", 100)/100):
at = text.get("at", None)
if at is not None:
if isinstance(at, dict):
if at:
at = random.choices(list(at.keys()),
weights=list(at.values()), k=1)[0]
else:
raise OptionError("\"at\" must be a valid string or weighted list of strings!")
given_text = text.get("text", [])
if isinstance(given_text, dict):
if not given_text:
given_text = []
else:
given_text = random.choices(list(given_text.keys()),
weights=list(given_text.values()), k=1)
if isinstance(given_text, str):
given_text = [given_text]
texts.append(PlandoText(
@ -942,12 +1007,13 @@ class PlandoTexts(Option[typing.List[PlandoText]], VerifyKeys):
given_text,
text.get("percentage", 100)
))
else:
raise OptionError("\"at\" must be a valid string or weighted list of strings!")
elif isinstance(text, PlandoText):
if random.random() < float(text.percentage/100):
texts.append(text)
else:
raise Exception(f"Cannot create plando text from non-dictionary type, got {type(text)}")
cls.verify_keys([text.at for text in texts])
return cls(texts)
else:
raise NotImplementedError(f"Cannot Convert from non-list, got {type(data)}")
@ -1053,11 +1119,11 @@ class PlandoConnections(Option[typing.List[PlandoConnection]], metaclass=Connect
used_entrances.append(entrance)
used_exits.append(exit)
if not cls.validate_entrance_name(entrance):
raise ValueError(f"{entrance.title()} is not a valid entrance.")
raise ValueError(f"'{entrance.title()}' is not a valid entrance.")
if not cls.validate_exit_name(exit):
raise ValueError(f"{exit.title()} is not a valid exit.")
raise ValueError(f"'{exit.title()}' is not a valid exit.")
if not cls.can_connect(entrance, exit):
raise ValueError(f"Connection between {entrance.title()} and {exit.title()} is invalid.")
raise ValueError(f"Connection between '{entrance.title()}' and '{exit.title()}' is invalid.")
@classmethod
def from_any(cls, data: PlandoConFromAnyType) -> Self:
@ -1120,27 +1186,48 @@ class PlandoConnections(Option[typing.List[PlandoConnection]], metaclass=Connect
class Accessibility(Choice):
"""Set rules for reachability of your items/locations.
Locations: ensure everything can be reached and acquired.
Items: ensure all logically relevant items can be acquired.
Minimal: ensure what is needed to reach your goal can be acquired."""
"""
Set rules for reachability of your items/locations.
**Full:** ensure everything can be reached and acquired.
**Minimal:** ensure what is needed to reach your goal can be acquired.
"""
display_name = "Accessibility"
option_locations = 0
option_items = 1
rich_text_doc = True
option_full = 0
option_minimal = 2
alias_none = 2
alias_locations = 0
alias_items = 0
default = 0
class ItemsAccessibility(Accessibility):
"""
Set rules for reachability of your items/locations.
**Full:** ensure everything can be reached and acquired.
**Minimal:** ensure what is needed to reach your goal can be acquired.
**Items:** ensure all logically relevant items can be acquired. Some items, such as keys, may be self-locking, and
some locations may be inaccessible.
"""
option_items = 1
default = 1
class ProgressionBalancing(NamedRange):
"""
A system that can move progression earlier, to try and prevent the player from getting stuck and bored early.
"""A system that can move progression earlier, to try and prevent the player from getting stuck and bored early.
A lower setting means more getting stuck. A higher setting means less getting stuck.
"""
default = 50
range_start = 0
range_end = 99
display_name = "Progression Balancing"
rich_text_doc = True
special_range_names = {
"disabled": 0,
"normal": 50,
@ -1170,13 +1257,18 @@ class CommonOptions(metaclass=OptionsMetaProperty):
progression_balancing: ProgressionBalancing
accessibility: Accessibility
def as_dict(self, *option_names: str, casing: str = "snake") -> typing.Dict[str, typing.Any]:
def as_dict(self,
*option_names: str,
casing: typing.Literal["snake", "camel", "pascal", "kebab"] = "snake",
toggles_as_bools: bool = False) -> typing.Dict[str, typing.Any]:
"""
Returns a dictionary of [str, Option.value]
:param option_names: names of the options to return
:param casing: case of the keys to return. Supports `snake`, `camel`, `pascal`, `kebab`
:param toggles_as_bools: whether toggle options should be output as bools instead of strings
"""
assert option_names, "options.as_dict() was used without any option names."
option_results = {}
for option_name in option_names:
if option_name in type(self).type_hints:
@ -1196,6 +1288,8 @@ class CommonOptions(metaclass=OptionsMetaProperty):
value = getattr(self, option_name).value
if isinstance(value, set):
value = sorted(value)
elif toggles_as_bools and issubclass(type(self).type_hints[option_name], Toggle):
value = bool(value)
option_results[display_name] = value
else:
raise ValueError(f"{option_name} not found in {tuple(type(self).type_hints)}")
@ -1205,29 +1299,36 @@ class CommonOptions(metaclass=OptionsMetaProperty):
class LocalItems(ItemSet):
"""Forces these items to be in their native world."""
display_name = "Local Items"
rich_text_doc = True
class NonLocalItems(ItemSet):
"""Forces these items to be outside their native world."""
display_name = "Non-local Items"
rich_text_doc = True
class StartInventory(ItemDict):
"""Start with these items."""
verify_item_name = True
display_name = "Start Inventory"
rich_text_doc = True
class StartInventoryPool(StartInventory):
"""Start with these items and don't place them in the world.
The game decides what the replacement items will be."""
The game decides what the replacement items will be.
"""
verify_item_name = True
display_name = "Start Inventory from Pool"
rich_text_doc = True
class StartHints(ItemSet):
"""Start with these item's locations prefilled into the !hint command."""
"""Start with these item's locations prefilled into the ``!hint`` command."""
display_name = "Start Hints"
rich_text_doc = True
class LocationSet(OptionSet):
@ -1236,28 +1337,33 @@ class LocationSet(OptionSet):
class StartLocationHints(LocationSet):
"""Start with these locations and their item prefilled into the !hint command"""
"""Start with these locations and their item prefilled into the ``!hint`` command."""
display_name = "Start Location Hints"
rich_text_doc = True
class ExcludeLocations(LocationSet):
"""Prevent these locations from having an important item"""
"""Prevent these locations from having an important item."""
display_name = "Excluded Locations"
rich_text_doc = True
class PriorityLocations(LocationSet):
"""Prevent these locations from having an unimportant item"""
"""Prevent these locations from having an unimportant item."""
display_name = "Priority Locations"
rich_text_doc = True
class DeathLink(Toggle):
"""When you die, everyone dies. Of course the reverse is true too."""
"""When you die, everyone who enabled death link dies. Of course, the reverse is true too."""
display_name = "Death Link"
rich_text_doc = True
class ItemLinks(OptionList):
"""Share part of your item pool with other players."""
display_name = "Item Links"
rich_text_doc = True
default = []
schema = Schema([
{
@ -1281,8 +1387,8 @@ class ItemLinks(OptionList):
picks_group = get_fuzzy_results(item_name, world.item_name_groups.keys(), limit=1)
picks_group = f" or '{picks_group[0][0]}' ({picks_group[0][1]}% sure)" if allow_item_groups else ""
raise Exception(f"Item {item_name} from item link {item_link} "
f"is not a valid item from {world.game} for {pool_name}. "
raise Exception(f"Item '{item_name}' from item link '{item_link}' "
f"is not a valid item from '{world.game}' for '{pool_name}'. "
f"Did you mean '{picks[0][0]}' ({picks[0][1]}% sure){picks_group}")
if allow_item_groups:
pool |= world.item_name_groups.get(item_name, {item_name})
@ -1324,6 +1430,7 @@ class ItemLinks(OptionList):
class Removed(FreeText):
"""This Option has been Removed."""
rich_text_doc = True
default = ""
visibility = Visibility.none
@ -1372,22 +1479,26 @@ it.
def get_option_groups(world: typing.Type[World], visibility_level: Visibility = Visibility.template) -> typing.Dict[
str, typing.Dict[str, typing.Type[Option[typing.Any]]]]:
"""Generates and returns a dictionary for the option groups of a specified world."""
option_groups = {option: option_group.name
for option_group in world.web.option_groups
for option in option_group.options}
option_to_name = {option: option_name for option_name, option in world.options_dataclass.type_hints.items()}
ordered_groups = {group.name: group.options for group in world.web.option_groups}
# add a default option group for uncategorized options to get thrown into
ordered_groups = ["Game Options"]
[ordered_groups.append(group) for group in option_groups.values() if group not in ordered_groups]
grouped_options = {group: {} for group in ordered_groups}
for option_name, option in world.options_dataclass.type_hints.items():
if visibility_level & option.visibility:
grouped_options[option_groups.get(option, "Game Options")][option_name] = option
if "Game Options" not in ordered_groups:
grouped_options = set(option for group in ordered_groups.values() for option in group)
ungrouped_options = [option for option in option_to_name if option not in grouped_options]
# only add the game options group if we have ungrouped options
if ungrouped_options:
ordered_groups = {**{"Game Options": ungrouped_options}, **ordered_groups}
# if the world doesn't have any ungrouped options, this group will be empty so just remove it
if not grouped_options["Game Options"]:
del grouped_options["Game Options"]
return grouped_options
return {
group: {
option_to_name[option]: option
for option in group_options
if (visibility_level in option.visibility and option in option_to_name)
}
for group, group_options in ordered_groups.items()
}
def generate_yaml_templates(target_folder: typing.Union[str, "pathlib.Path"], generate_hidden: bool = True) -> None:
@ -1426,46 +1537,61 @@ def generate_yaml_templates(target_folder: typing.Union[str, "pathlib.Path"], ge
return data, notes
def yaml_dump_scalar(scalar) -> str:
# yaml dump may add end of document marker and newlines.
return yaml.dump(scalar).replace("...\n", "").strip()
for game_name, world in AutoWorldRegister.world_types.items():
if not world.hidden or generate_hidden:
grouped_options = get_option_groups(world)
option_groups = get_option_groups(world)
with open(local_path("data", "options.yaml")) as f:
file_data = f.read()
res = Template(file_data).render(
option_groups=grouped_options,
__version__=__version__, game=game_name, yaml_dump=yaml.dump,
option_groups=option_groups,
__version__=__version__, game=game_name, yaml_dump=yaml_dump_scalar,
dictify_range=dictify_range,
)
del file_data
with open(os.path.join(target_folder, game_name + ".yaml"), "w", encoding="utf-8-sig") as f:
with open(os.path.join(target_folder, get_file_safe_name(game_name) + ".yaml"), "w", encoding="utf-8-sig") as f:
f.write(res)
if __name__ == "__main__":
def dump_player_options(multiworld: MultiWorld) -> None:
from csv import DictWriter
from worlds.alttp.Options import Logic
import argparse
game_players = defaultdict(list)
for player, game in multiworld.game.items():
game_players[game].append(player)
game_players = dict(sorted(game_players.items()))
map_shuffle = Toggle
compass_shuffle = Toggle
key_shuffle = Toggle
big_key_shuffle = Toggle
hints = Toggle
test = argparse.Namespace()
test.logic = Logic.from_text("no_logic")
test.map_shuffle = map_shuffle.from_text("ON")
test.hints = hints.from_text('OFF')
try:
test.logic = Logic.from_text("overworld_glitches_typo")
except KeyError as e:
print(e)
try:
test.logic_owg = Logic.from_text("owg")
except KeyError as e:
print(e)
if test.map_shuffle:
print("map_shuffle is on")
print(f"Hints are {bool(test.hints)}")
print(test)
output = []
per_game_option_names = [
getattr(option, "display_name", option_key)
for option_key, option in PerGameCommonOptions.type_hints.items()
]
all_option_names = per_game_option_names.copy()
for game, players in game_players.items():
game_option_names = per_game_option_names.copy()
for player in players:
world = multiworld.worlds[player]
player_output = {
"Game": multiworld.game[player],
"Name": multiworld.get_player_name(player),
}
output.append(player_output)
for option_key, option in world.options_dataclass.type_hints.items():
if option.visibility == Visibility.none:
continue
display_name = getattr(option, "display_name", option_key)
player_output[display_name] = getattr(world.options, option_key).current_option_name
if display_name not in game_option_names:
all_option_names.append(display_name)
game_option_names.append(display_name)
with open(output_path(f"generate_{multiworld.seed_name}.csv"), mode="w", newline="") as file:
fields = ["Game", "Name", *all_option_names]
writer = DictWriter(file, fields)
writer.writeheader()
writer.writerows(output)

View File

@ -72,6 +72,14 @@ Currently, the following games are supported:
* Aquaria
* Yu-Gi-Oh! Ultimate Masters: World Championship Tournament 2006
* A Hat in Time
* Old School Runescape
* Kingdom Hearts 1
* Mega Man 2
* Yacht Dice
* Faxanadu
* Saving Princess
* Castlevania: Circle of the Moon
* Inscryption
For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/).
Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled

View File

@ -243,6 +243,9 @@ class SNIContext(CommonContext):
# Once the games handled by SNIClient gets made to be remote items,
# this will no longer be needed.
async_start(self.send_msgs([{"cmd": "LocationScouts", "locations": list(new_locations)}]))
if self.client_handler is not None:
self.client_handler.on_package(self, cmd, args)
def run_gui(self) -> None:
from kvui import GameManager
@ -633,7 +636,13 @@ async def game_watcher(ctx: SNIContext) -> None:
if not ctx.client_handler:
continue
rom_validated = await ctx.client_handler.validate_rom(ctx)
try:
rom_validated = await ctx.client_handler.validate_rom(ctx)
except Exception as e:
snes_logger.error(f"An error occurred, see logs for details: {e}")
text_file_logger = logging.getLogger()
text_file_logger.exception(e)
rom_validated = False
if not rom_validated or (ctx.auth and ctx.auth != ctx.rom):
snes_logger.warning("ROM change detected, please reconnect to the multiworld server")
@ -649,7 +658,13 @@ async def game_watcher(ctx: SNIContext) -> None:
perf_counter = time.perf_counter()
await ctx.client_handler.game_watcher(ctx)
try:
await ctx.client_handler.game_watcher(ctx)
except Exception as e:
snes_logger.error(f"An error occurred, see logs for details: {e}")
text_file_logger = logging.getLogger()
text_file_logger.exception(e)
await snes_disconnect(ctx)
async def run_game(romfile: str) -> None:

View File

@ -29,7 +29,7 @@ class UndertaleCommandProcessor(ClientCommandProcessor):
def _cmd_patch(self):
"""Patch the game. Only use this command if /auto_patch fails."""
if isinstance(self.ctx, UndertaleContext):
os.makedirs(name=os.path.join(os.getcwd(), "Undertale"), exist_ok=True)
os.makedirs(name=Utils.user_path("Undertale"), exist_ok=True)
self.ctx.patch_game()
self.output("Patched.")
@ -43,7 +43,7 @@ class UndertaleCommandProcessor(ClientCommandProcessor):
def _cmd_auto_patch(self, steaminstall: typing.Optional[str] = None):
"""Patch the game automatically."""
if isinstance(self.ctx, UndertaleContext):
os.makedirs(name=os.path.join(os.getcwd(), "Undertale"), exist_ok=True)
os.makedirs(name=Utils.user_path("Undertale"), exist_ok=True)
tempInstall = steaminstall
if not os.path.isfile(os.path.join(tempInstall, "data.win")):
tempInstall = None
@ -62,7 +62,7 @@ class UndertaleCommandProcessor(ClientCommandProcessor):
for file_name in os.listdir(tempInstall):
if file_name != "steam_api.dll":
shutil.copy(os.path.join(tempInstall, file_name),
os.path.join(os.getcwd(), "Undertale", file_name))
Utils.user_path("Undertale", file_name))
self.ctx.patch_game()
self.output("Patching successful!")
@ -111,12 +111,12 @@ class UndertaleContext(CommonContext):
self.save_game_folder = os.path.expandvars(r"%localappdata%/UNDERTALE")
def patch_game(self):
with open(os.path.join(os.getcwd(), "Undertale", "data.win"), "rb") as f:
with open(Utils.user_path("Undertale", "data.win"), "rb") as f:
patchedFile = bsdiff4.patch(f.read(), undertale.data_path("patch.bsdiff"))
with open(os.path.join(os.getcwd(), "Undertale", "data.win"), "wb") as f:
with open(Utils.user_path("Undertale", "data.win"), "wb") as f:
f.write(patchedFile)
os.makedirs(name=os.path.join(os.getcwd(), "Undertale", "Custom Sprites"), exist_ok=True)
with open(os.path.expandvars(os.path.join(os.getcwd(), "Undertale", "Custom Sprites",
os.makedirs(name=Utils.user_path("Undertale", "Custom Sprites"), exist_ok=True)
with open(os.path.expandvars(Utils.user_path("Undertale", "Custom Sprites",
"Which Character.txt")), "w") as f:
f.writelines(["// Put the folder name of the sprites you want to play as, make sure it is the only "
"line other than this one.\n", "frisk"])
@ -247,8 +247,8 @@ async def process_undertale_cmd(ctx: UndertaleContext, cmd: str, args: dict):
with open(os.path.join(ctx.save_game_folder, filename), "w") as f:
toDraw = ""
for i in range(20):
if i < len(str(ctx.item_names.lookup_in_slot(l.item))):
toDraw += str(ctx.item_names.lookup_in_slot(l.item))[i]
if i < len(str(ctx.item_names.lookup_in_game(l.item))):
toDraw += str(ctx.item_names.lookup_in_game(l.item))[i]
else:
break
f.write(toDraw)

107
Utils.py
View File

@ -18,8 +18,8 @@ import warnings
from argparse import Namespace
from settings import Settings, get_settings
from typing import BinaryIO, Coroutine, Optional, Set, Dict, Any, Union
from typing_extensions import TypeGuard
from time import sleep
from typing import BinaryIO, Coroutine, Optional, Set, Dict, Any, Union, TypeGuard
from yaml import load, load_all, dump
try:
@ -31,6 +31,7 @@ if typing.TYPE_CHECKING:
import tkinter
import pathlib
from BaseClasses import Region
import multiprocessing
def tuplize_version(version: str) -> Version:
@ -46,7 +47,7 @@ class Version(typing.NamedTuple):
return ".".join(str(item) for item in self)
__version__ = "0.5.0"
__version__ = "0.6.0"
version_tuple = tuplize_version(__version__)
is_linux = sys.platform.startswith("linux")
@ -151,8 +152,15 @@ def home_path(*path: str) -> str:
if hasattr(home_path, 'cached_path'):
pass
elif sys.platform.startswith('linux'):
home_path.cached_path = os.path.expanduser('~/Archipelago')
os.makedirs(home_path.cached_path, 0o700, exist_ok=True)
xdg_data_home = os.getenv('XDG_DATA_HOME', os.path.expanduser('~/.local/share'))
home_path.cached_path = xdg_data_home + '/Archipelago'
if not os.path.isdir(home_path.cached_path):
legacy_home_path = os.path.expanduser('~/Archipelago')
if os.path.isdir(legacy_home_path):
os.renames(legacy_home_path, home_path.cached_path)
os.symlink(home_path.cached_path, legacy_home_path)
else:
os.makedirs(home_path.cached_path, 0o700, exist_ok=True)
else:
# not implemented
home_path.cached_path = local_path() # this will generate the same exceptions we got previously
@ -420,10 +428,11 @@ class RestrictedUnpickler(pickle.Unpickler):
if module == "builtins" and name in safe_builtins:
return getattr(builtins, name)
# used by MultiServer -> savegame/multidata
if module == "NetUtils" and name in {"NetworkItem", "ClientStatus", "Hint", "SlotType", "NetworkSlot"}:
if module == "NetUtils" and name in {"NetworkItem", "ClientStatus", "Hint",
"SlotType", "NetworkSlot", "HintStatus"}:
return getattr(self.net_utils_module, name)
# Options and Plando are unpickled by WebHost -> Generate
if module == "worlds.generic" and name in {"PlandoItem", "PlandoConnection"}:
if module == "worlds.generic" and name == "PlandoItem":
if not self.generic_properties_module:
self.generic_properties_module = importlib.import_module("worlds.generic")
return getattr(self.generic_properties_module, name)
@ -434,7 +443,7 @@ class RestrictedUnpickler(pickle.Unpickler):
else:
mod = importlib.import_module(module)
obj = getattr(mod, name)
if issubclass(obj, self.options_module.Option):
if issubclass(obj, (self.options_module.Option, self.options_module.PlandoConnection)):
return obj
# Forbid everything else.
raise pickle.UnpicklingError(f"global '{module}.{name}' is forbidden")
@ -483,9 +492,9 @@ def get_text_after(text: str, start: str) -> str:
loglevel_mapping = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}
def init_logging(name: str, loglevel: typing.Union[str, int] = logging.INFO, write_mode: str = "w",
log_format: str = "[%(name)s at %(asctime)s]: %(message)s",
exception_logger: typing.Optional[str] = None):
def init_logging(name: str, loglevel: typing.Union[str, int] = logging.INFO,
write_mode: str = "w", log_format: str = "[%(name)s at %(asctime)s]: %(message)s",
add_timestamp: bool = False, exception_logger: typing.Optional[str] = None):
import datetime
loglevel: int = loglevel_mapping.get(loglevel, loglevel)
log_folder = user_path("logs")
@ -512,11 +521,15 @@ def init_logging(name: str, loglevel: typing.Union[str, int] = logging.INFO, wri
def filter(self, record: logging.LogRecord) -> bool:
return self.condition(record)
file_handler.addFilter(Filter("NoStream", lambda record: not getattr(record, "NoFile", False)))
file_handler.addFilter(Filter("NoStream", lambda record: not getattr(record, "NoFile", False)))
file_handler.addFilter(Filter("NoCarriageReturn", lambda record: '\r' not in record.getMessage()))
root_logger.addHandler(file_handler)
if sys.stdout:
formatter = logging.Formatter(fmt='[%(asctime)s] %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
stream_handler = logging.StreamHandler(sys.stdout)
stream_handler.addFilter(Filter("NoFile", lambda record: not getattr(record, "NoStream", False)))
if add_timestamp:
stream_handler.setFormatter(formatter)
root_logger.addHandler(stream_handler)
# Relay unhandled exceptions to logger.
@ -528,7 +541,8 @@ def init_logging(name: str, loglevel: typing.Union[str, int] = logging.INFO, wri
sys.__excepthook__(exc_type, exc_value, exc_traceback)
return
logging.getLogger(exception_logger).exception("Uncaught exception",
exc_info=(exc_type, exc_value, exc_traceback))
exc_info=(exc_type, exc_value, exc_traceback),
extra={"NoStream": exception_logger is None})
return orig_hook(exc_type, exc_value, exc_traceback)
handle_exception._wrapped = True
@ -551,7 +565,7 @@ def init_logging(name: str, loglevel: typing.Union[str, int] = logging.INFO, wri
import platform
logging.info(
f"Archipelago ({__version__}) logging initialized"
f" on {platform.platform()}"
f" on {platform.platform()} process {os.getpid()}"
f" running Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
f"{' (frozen)' if is_frozen() else ''}"
)
@ -567,6 +581,8 @@ def stream_input(stream: typing.TextIO, queue: "asyncio.Queue[str]"):
else:
if text:
queue.put_nowait(text)
else:
sleep(0.01) # non-blocking stream
from threading import Thread
thread = Thread(target=queuer, name=f"Stream handler for {stream.name}", daemon=True)
@ -664,6 +680,19 @@ def get_input_text_from_response(text: str, command: str) -> typing.Optional[str
return None
def is_kivy_running() -> bool:
if "kivy" in sys.modules:
from kivy.app import App
return App.get_running_app() is not None
return False
def _mp_open_filename(res: "multiprocessing.Queue[typing.Optional[str]]", *args: Any) -> None:
if is_kivy_running():
raise RuntimeError("kivy should not be running in multiprocess")
res.put(open_filename(*args))
def open_filename(title: str, filetypes: typing.Iterable[typing.Tuple[str, typing.Iterable[str]]], suggest: str = "") \
-> typing.Optional[str]:
logging.info(f"Opening file input dialog for {title}.")
@ -693,6 +722,13 @@ def open_filename(title: str, filetypes: typing.Iterable[typing.Tuple[str, typin
f'This attempt was made because open_filename was used for "{title}".')
raise e
else:
if is_macos and is_kivy_running():
# on macOS, mixing kivy and tk does not work, so spawn a new process
# FIXME: performance of this is pretty bad, and we should (also) look into alternatives
from multiprocessing import Process, Queue
res: "Queue[typing.Optional[str]]" = Queue()
Process(target=_mp_open_filename, args=(res, title, filetypes, suggest)).start()
return res.get()
try:
root = tkinter.Tk()
except tkinter.TclError:
@ -702,6 +738,12 @@ def open_filename(title: str, filetypes: typing.Iterable[typing.Tuple[str, typin
initialfile=suggest or None)
def _mp_open_directory(res: "multiprocessing.Queue[typing.Optional[str]]", *args: Any) -> None:
if is_kivy_running():
raise RuntimeError("kivy should not be running in multiprocess")
res.put(open_directory(*args))
def open_directory(title: str, suggest: str = "") -> typing.Optional[str]:
def run(*args: str):
return subprocess.run(args, capture_output=True, text=True).stdout.split("\n", 1)[0] or None
@ -725,9 +767,16 @@ def open_directory(title: str, suggest: str = "") -> typing.Optional[str]:
import tkinter.filedialog
except Exception as e:
logging.error('Could not load tkinter, which is likely not installed. '
f'This attempt was made because open_filename was used for "{title}".')
f'This attempt was made because open_directory was used for "{title}".')
raise e
else:
if is_macos and is_kivy_running():
# on macOS, mixing kivy and tk does not work, so spawn a new process
# FIXME: performance of this is pretty bad, and we should (also) look into alternatives
from multiprocessing import Process, Queue
res: "Queue[typing.Optional[str]]" = Queue()
Process(target=_mp_open_directory, args=(res, title, suggest)).start()
return res.get()
try:
root = tkinter.Tk()
except tkinter.TclError:
@ -740,12 +789,6 @@ def messagebox(title: str, text: str, error: bool = False) -> None:
def run(*args: str):
return subprocess.run(args, capture_output=True, text=True).stdout.split("\n", 1)[0] or None
def is_kivy_running():
if "kivy" in sys.modules:
from kivy.app import App
return App.get_running_app() is not None
return False
if is_kivy_running():
from kvui import MessageBox
MessageBox(title, text, error).open()
@ -824,11 +867,10 @@ def async_start(co: Coroutine[None, None, typing.Any], name: Optional[str] = Non
task.add_done_callback(_faf_tasks.discard)
def deprecate(message: str):
def deprecate(message: str, add_stacklevels: int = 0):
if __debug__:
raise Exception(message)
import warnings
warnings.warn(message)
warnings.warn(message, stacklevel=2 + add_stacklevels)
class DeprecateDict(dict):
@ -842,10 +884,9 @@ class DeprecateDict(dict):
def __getitem__(self, item: Any) -> Any:
if self.should_error:
deprecate(self.log_message)
deprecate(self.log_message, add_stacklevels=1)
elif __debug__:
import warnings
warnings.warn(self.log_message)
warnings.warn(self.log_message, stacklevel=2)
return super().__getitem__(item)
@ -899,7 +940,7 @@ def freeze_support() -> None:
def visualize_regions(root_region: Region, file_name: str, *,
show_entrance_names: bool = False, show_locations: bool = True, show_other_regions: bool = True,
linetype_ortho: bool = True) -> None:
linetype_ortho: bool = True, regions_to_highlight: set[Region] | None = None) -> None:
"""Visualize the layout of a world as a PlantUML diagram.
:param root_region: The region from which to start the diagram from. (Usually the "Menu" region of your world.)
@ -915,16 +956,22 @@ def visualize_regions(root_region: Region, file_name: str, *,
Items without ID will be shown in italics.
:param show_other_regions: (default True) If enabled, regions that can't be reached by traversing exits are shown.
:param linetype_ortho: (default True) If enabled, orthogonal straight line parts will be used; otherwise polylines.
:param regions_to_highlight: Regions that will be highlighted in green if they are reachable.
Example usage in World code:
from Utils import visualize_regions
visualize_regions(self.multiworld.get_region("Menu", self.player), "my_world.puml")
state = self.multiworld.get_all_state(False)
state.update_reachable_regions(self.player)
visualize_regions(self.get_region("Menu"), "my_world.puml", show_entrance_names=True,
regions_to_highlight=state.reachable_regions[self.player])
Example usage in Main code:
from Utils import visualize_regions
for player in multiworld.player_ids:
visualize_regions(multiworld.get_region("Menu", player), f"{multiworld.get_out_file_name_base(player)}.puml")
"""
if regions_to_highlight is None:
regions_to_highlight = set()
assert root_region.multiworld, "The multiworld attribute of root_region has to be filled"
from BaseClasses import Entrance, Item, Location, LocationProgressType, MultiWorld, Region
from collections import deque
@ -977,7 +1024,7 @@ def visualize_regions(root_region: Region, file_name: str, *,
uml.append(f"\"{fmt(region)}\" : {{field}} {lock}{fmt(location)}")
def visualize_region(region: Region) -> None:
uml.append(f"class \"{fmt(region)}\"")
uml.append(f"class \"{fmt(region)}\" {'#00FF00' if region in regions_to_highlight else ''}")
if show_locations:
visualize_locations(region)
visualize_exits(region)

View File

@ -176,7 +176,7 @@ class WargrooveContext(CommonContext):
if not os.path.isfile(path):
open(path, 'w').close()
# Announcing commander unlocks
item_name = self.item_names.lookup_in_slot(network_item.item)
item_name = self.item_names.lookup_in_game(network_item.item)
if item_name in faction_table.keys():
for commander in faction_table[item_name]:
logger.info(f"{commander.name} has been unlocked!")
@ -197,7 +197,7 @@ class WargrooveContext(CommonContext):
open(print_path, 'w').close()
with open(print_path, 'w') as f:
f.write("Received " +
self.item_names.lookup_in_slot(network_item.item) +
self.item_names.lookup_in_game(network_item.item) +
" from " +
self.player_names[network_item.player])
f.close()
@ -267,9 +267,7 @@ class WargrooveContext(CommonContext):
def build(self):
container = super().build()
panel = TabbedPanelItem(text="Wargroove")
panel.content = self.build_tracker()
self.tabs.add_widget(panel)
self.add_client_tab("Wargroove", self.build_tracker())
return container
def build_tracker(self) -> TrackerLayout:
@ -342,7 +340,7 @@ class WargrooveContext(CommonContext):
faction_items = 0
faction_item_names = [faction + ' Commanders' for faction in faction_table.keys()]
for network_item in self.items_received:
if self.item_names.lookup_in_slot(network_item.item) in faction_item_names:
if self.item_names.lookup_in_game(network_item.item) in faction_item_names:
faction_items += 1
starting_groove = (faction_items - 1) * self.starting_groove_multiplier
# Must be an integer larger than 0

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python3
import argparse
import os
import multiprocessing
import logging
@ -13,11 +14,12 @@ ModuleUpdate.update()
# in case app gets imported by something like gunicorn
import Utils
import settings
from Utils import get_file_safe_name
if typing.TYPE_CHECKING:
from flask import Flask
Utils.local_path.cached_path = os.path.dirname(__file__) or "." # py3.8 is not abs. remove "." when dropping 3.8
Utils.local_path.cached_path = os.path.dirname(__file__)
settings.no_gui = True
configpath = os.path.abspath("config.yaml")
if not os.path.exists(configpath): # fall back to config.yaml in home
@ -33,6 +35,15 @@ def get_app() -> "Flask":
import yaml
app.config.from_file(configpath, yaml.safe_load)
logging.info(f"Updated config from {configpath}")
# inside get_app() so it's usable in systems like gunicorn, which do not run WebHost.py, but import it.
parser = argparse.ArgumentParser(allow_abbrev=False)
parser.add_argument('--config_override', default=None,
help="Path to yaml config file that overrules config.yaml.")
args = parser.parse_known_args()[0]
if args.config_override:
import yaml
app.config.from_file(os.path.abspath(args.config_override), yaml.safe_load)
logging.info(f"Updated config from {args.config_override}")
if not app.config["HOST_ADDRESS"]:
logging.info("Getting public IP, as HOST_ADDRESS is empty.")
app.config["HOST_ADDRESS"] = Utils.get_public_ipv4()
@ -60,9 +71,10 @@ def create_ordered_tutorials_file() -> typing.List[typing.Dict[str, typing.Any]]
worlds[game] = world
base_target_path = Utils.local_path("WebHostLib", "static", "generated", "docs")
shutil.rmtree(base_target_path, ignore_errors=True)
for game, world in worlds.items():
# copy files from world's docs folder to the generated folder
target_path = os.path.join(base_target_path, game)
target_path = os.path.join(base_target_path, get_file_safe_name(game))
os.makedirs(target_path, exist_ok=True)
if world.zip_path:

View File

@ -9,7 +9,7 @@ from flask_compress import Compress
from pony.flask import Pony
from werkzeug.routing import BaseConverter
from Utils import title_sorted
from Utils import title_sorted, get_file_safe_name
UPLOAD_FOLDER = os.path.relpath('uploads')
LOGS_FOLDER = os.path.relpath('logs')
@ -20,6 +20,7 @@ Pony(app)
app.jinja_env.filters['any'] = any
app.jinja_env.filters['all'] = all
app.jinja_env.filters['get_file_safe_name'] = get_file_safe_name
app.config["SELFHOST"] = True # application process is in charge of running the websites
app.config["GENERATORS"] = 8 # maximum concurrent world gens
@ -38,6 +39,8 @@ app.config["SECRET_KEY"] = bytes(socket.gethostname(), encoding="utf-8")
app.config["JOB_THRESHOLD"] = 1
# after what time in seconds should generation be aborted, freeing the queue slot. Can be set to None to disable.
app.config["JOB_TIME"] = 600
# memory limit for generator processes in bytes
app.config["GENERATOR_MEMORY_LIMIT"] = 4294967296
app.config['SESSION_PERMANENT'] = True
# waitress uses one thread for I/O, these are for processing of views that then get sent
@ -84,6 +87,6 @@ def register():
from WebHostLib.customserver import run_server_process
# to trigger app routing picking up on it
from . import tracker, upload, landing, check, generate, downloads, api, stats, misc, robots, options
from . import tracker, upload, landing, check, generate, downloads, api, stats, misc, robots, options, session
app.register_blueprint(api.api_endpoints)

View File

@ -1,51 +1,15 @@
"""API endpoints package."""
from typing import List, Tuple
from uuid import UUID
from flask import Blueprint, abort, url_for
from flask import Blueprint
import worlds.Files
from ..models import Room, Seed
from ..models import Seed, Slot
api_endpoints = Blueprint('api', __name__, url_prefix="/api")
# unsorted/misc endpoints
def get_players(seed: Seed) -> List[Tuple[str, str]]:
return [(slot.player_name, slot.game) for slot in seed.slots]
return [(slot.player_name, slot.game) for slot in seed.slots.order_by(Slot.player_id)]
@api_endpoints.route('/room_status/<suuid:room>')
def room_info(room: UUID):
room = Room.get(id=room)
if room is None:
return abort(404)
def supports_apdeltapatch(game: str):
return game in worlds.Files.AutoPatchRegister.patch_types
downloads = []
for slot in sorted(room.seed.slots):
if slot.data and not supports_apdeltapatch(slot.game):
slot_download = {
"slot": slot.player_id,
"download": url_for("download_slot_file", room_id=room.id, player_id=slot.player_id)
}
downloads.append(slot_download)
elif slot.data:
slot_download = {
"slot": slot.player_id,
"download": url_for("download_patch", patch_id=slot.id, room_id=room.id)
}
downloads.append(slot_download)
return {
"tracker": room.tracker,
"players": get_players(room.seed),
"last_port": room.last_port,
"last_activity": room.last_activity,
"timeout": room.timeout,
"downloads": downloads,
}
from . import generate, user, datapackage # trigger registration
from . import datapackage, generate, room, user # trigger registration

42
WebHostLib/api/room.py Normal file
View File

@ -0,0 +1,42 @@
from typing import Any, Dict
from uuid import UUID
from flask import abort, url_for
import worlds.Files
from . import api_endpoints, get_players
from ..models import Room
@api_endpoints.route('/room_status/<suuid:room_id>')
def room_info(room_id: UUID) -> Dict[str, Any]:
room = Room.get(id=room_id)
if room is None:
return abort(404)
def supports_apdeltapatch(game: str) -> bool:
return game in worlds.Files.AutoPatchRegister.patch_types
downloads = []
for slot in sorted(room.seed.slots):
if slot.data and not supports_apdeltapatch(slot.game):
slot_download = {
"slot": slot.player_id,
"download": url_for("download_slot_file", room_id=room.id, player_id=slot.player_id)
}
downloads.append(slot_download)
elif slot.data:
slot_download = {
"slot": slot.player_id,
"download": url_for("download_patch", patch_id=slot.id, room_id=room.id)
}
downloads.append(slot_download)
return {
"tracker": room.tracker,
"players": get_players(room.seed),
"last_port": room.last_port,
"last_activity": room.last_activity,
"timeout": room.timeout,
"downloads": downloads,
}

View File

@ -30,4 +30,4 @@ def get_seeds():
"creation_time": seed.creation_time,
"players": get_players(seed.slots),
})
return jsonify(response)
return jsonify(response)

View File

@ -6,6 +6,7 @@ import multiprocessing
import typing
from datetime import timedelta, datetime
from threading import Event, Thread
from typing import Any
from uuid import UUID
from pony.orm import db_session, select, commit
@ -53,7 +54,21 @@ def launch_generator(pool: multiprocessing.pool.Pool, generation: Generation):
generation.state = STATE_STARTED
def init_db(pony_config: dict):
def init_generator(config: dict[str, Any]) -> None:
try:
import resource
except ModuleNotFoundError:
pass # unix only module
else:
# set soft limit for memory to from config (default 4GiB)
soft_limit = config["GENERATOR_MEMORY_LIMIT"]
old_limit, hard_limit = resource.getrlimit(resource.RLIMIT_AS)
if soft_limit != old_limit:
resource.setrlimit(resource.RLIMIT_AS, (soft_limit, hard_limit))
logging.debug(f"Changed AS mem limit {old_limit} -> {soft_limit}")
del resource, soft_limit, hard_limit
pony_config = config["PONY"]
db.bind(**pony_config)
db.generate_mapping()
@ -105,8 +120,8 @@ def autogen(config: dict):
try:
with Locker("autogen"):
with multiprocessing.Pool(config["GENERATORS"], initializer=init_db,
initargs=(config["PONY"],), maxtasksperchild=10) as generator_pool:
with multiprocessing.Pool(config["GENERATORS"], initializer=init_generator,
initargs=(config,), maxtasksperchild=10) as generator_pool:
with db_session:
to_start = select(generation for generation in Generation if generation.state == STATE_STARTED)

View File

@ -105,8 +105,9 @@ def roll_options(options: Dict[str, Union[dict, str]],
plando_options=plando_options)
else:
for i, yaml_data in enumerate(yaml_datas):
rolled_results[f"{filename}/{i + 1}"] = roll_settings(yaml_data,
plando_options=plando_options)
if yaml_data is not None:
rolled_results[f"{filename}/{i + 1}"] = roll_settings(yaml_data,
plando_options=plando_options)
except Exception as e:
if e.__cause__:
results[filename] = f"Failed to generate options in {filename}: {e} - {e.__cause__}"

View File

@ -72,6 +72,14 @@ class WebHostContext(Context):
self.video = {}
self.tags = ["AP", "WebHost"]
def __del__(self):
try:
import psutil
from Utils import format_SI_prefix
self.logger.debug(f"Context destroyed, Mem: {format_SI_prefix(psutil.Process().memory_info().rss, 1024)}iB")
except ImportError:
self.logger.debug("Context destroyed")
def _load_game_data(self):
for key, value in self.static_server_data.items():
# NOTE: attributes are mutable and shared, so they will have to be copied before being modified
@ -249,6 +257,7 @@ def run_server_process(name: str, ponyconfig: dict, static_server_data: dict,
ctx = WebHostContext(static_server_data, logger)
ctx.load(room_id)
ctx.init_save()
assert ctx.server is None
try:
ctx.server = websockets.serve(
functools.partial(server, ctx=ctx), ctx.host, ctx.port, ssl=ssl_context)
@ -279,6 +288,7 @@ def run_server_process(name: str, ponyconfig: dict, static_server_data: dict,
ctx.auto_shutdown = Room.get(id=room_id).timeout
if ctx.saving:
setattr(asyncio.current_task(), "save", lambda: ctx._save(True))
assert ctx.shutdown_task is None
ctx.shutdown_task = asyncio.create_task(auto_shutdown(ctx, []))
await ctx.shutdown_task
@ -325,10 +335,12 @@ def run_server_process(name: str, ponyconfig: dict, static_server_data: dict,
def run(self):
while 1:
next_room = rooms_to_run.get(block=True, timeout=None)
gc.collect()
task = asyncio.run_coroutine_threadsafe(start_room(next_room), loop)
self._tasks.append(task)
task.add_done_callback(self._done)
logging.info(f"Starting room {next_room} on {name}.")
del task # delete reference to task object
starter = Starter()
starter.daemon = True

View File

@ -31,11 +31,11 @@ def get_meta(options_source: dict, race: bool = False) -> Dict[str, Union[List[s
server_options = {
"hint_cost": int(options_source.get("hint_cost", ServerOptions.hint_cost)),
"release_mode": options_source.get("release_mode", ServerOptions.release_mode),
"remaining_mode": options_source.get("remaining_mode", ServerOptions.remaining_mode),
"collect_mode": options_source.get("collect_mode", ServerOptions.collect_mode),
"release_mode": str(options_source.get("release_mode", ServerOptions.release_mode)),
"remaining_mode": str(options_source.get("remaining_mode", ServerOptions.remaining_mode)),
"collect_mode": str(options_source.get("collect_mode", ServerOptions.collect_mode)),
"item_cheat": bool(int(options_source.get("item_cheat", not ServerOptions.disable_item_cheat))),
"server_password": options_source.get("server_password", None),
"server_password": str(options_source.get("server_password", None)),
}
generator_options = {
"spoiler": int(options_source.get("spoiler", GeneratorOptions.spoiler)),
@ -81,6 +81,7 @@ def start_generation(options: Dict[str, Union[dict, str]], meta: Dict[str, Any])
elif len(gen_options) > app.config["MAX_ROLL"]:
flash(f"Sorry, generating of multiworlds is limited to {app.config['MAX_ROLL']} players. "
f"If you have a larger group, please generate it yourself and upload it.")
return redirect(url_for(request.endpoint, **(request.view_args or {})))
elif len(gen_options) >= app.config["JOB_THRESHOLD"]:
gen = Generation(
options=pickle.dumps({name: vars(options) for name, options in gen_options.items()}),
@ -134,6 +135,7 @@ def gen_game(gen_options: dict, meta: Optional[Dict[str, Any]] = None, owner=Non
{"bosses", "items", "connections", "texts"}))
erargs.skip_prog_balancing = False
erargs.skip_output = False
erargs.csv_output = False
name_counter = Counter()
for player, (playerfile, settings) in enumerate(gen_options.items(), 1):

View File

@ -1,10 +1,11 @@
import datetime
import os
from typing import List, Dict, Union
from typing import Any, IO, Dict, Iterator, List, Tuple, Union
import jinja2.exceptions
from flask import request, redirect, url_for, render_template, Response, session, abort, send_from_directory
from pony.orm import count, commit, db_session
from werkzeug.utils import secure_filename
from worlds.AutoWorld import AutoWorldRegister
from . import app, cache
@ -17,13 +18,6 @@ def get_world_theme(game_name: str):
return 'grass'
@app.before_request
def register_session():
session.permanent = True # technically 31 days after the last visit
if not session.get("_id", None):
session["_id"] = uuid4() # uniquely identify each session without needing a login
@app.errorhandler(404)
@app.errorhandler(jinja2.exceptions.TemplateNotFound)
def page_not_found(err):
@ -69,14 +63,40 @@ def tutorial_landing():
@app.route('/faq/<string:lang>/')
@cache.cached()
def faq(lang):
return render_template("faq.html", lang=lang)
def faq(lang: str):
import markdown
with open(os.path.join(app.static_folder, "assets", "faq", secure_filename(lang)+".md")) as f:
document = f.read()
return render_template(
"markdown_document.html",
title="Frequently Asked Questions",
html_from_markdown=markdown.markdown(
document,
extensions=["toc", "mdx_breakless_lists"],
extension_configs={
"toc": {"anchorlink": True}
}
),
)
@app.route('/glossary/<string:lang>/')
@cache.cached()
def terms(lang):
return render_template("glossary.html", lang=lang)
def glossary(lang: str):
import markdown
with open(os.path.join(app.static_folder, "assets", "glossary", secure_filename(lang)+".md")) as f:
document = f.read()
return render_template(
"markdown_document.html",
title="Glossary",
html_from_markdown=markdown.markdown(
document,
extensions=["toc", "mdx_breakless_lists"],
extension_configs={
"toc": {"anchorlink": True}
}
),
)
@app.route('/seed/<suuid:seed>')
@ -97,49 +117,91 @@ def new_room(seed: UUID):
return redirect(url_for("host_room", room=room.id))
def _read_log(path: str):
if os.path.exists(path):
with open(path, encoding="utf-8-sig") as log:
yield from log
else:
yield f"Logfile {path} does not exist. " \
f"Likely a crash during spinup of multiworld instance or it is still spinning up."
def _read_log(log: IO[Any], offset: int = 0) -> Iterator[bytes]:
marker = log.read(3) # skip optional BOM
if marker != b'\xEF\xBB\xBF':
log.seek(0, os.SEEK_SET)
log.seek(offset, os.SEEK_CUR)
yield from log
log.close() # free file handle as soon as possible
@app.route('/log/<suuid:room>')
def display_log(room: UUID):
def display_log(room: UUID) -> Union[str, Response, Tuple[str, int]]:
room = Room.get(id=room)
if room is None:
return abort(404)
if room.owner == session["_id"]:
file_path = os.path.join("logs", str(room.id) + ".txt")
if os.path.exists(file_path):
return Response(_read_log(file_path), mimetype="text/plain;charset=UTF-8")
return "Log File does not exist."
try:
log = open(file_path, "rb")
range_header = request.headers.get("Range")
if range_header:
range_type, range_values = range_header.split('=')
start, end = map(str.strip, range_values.split('-', 1))
if range_type != "bytes" or end != "":
return "Unsupported range", 500
# NOTE: we skip Content-Range in the response here, which isn't great but works for our JS
return Response(_read_log(log, int(start)), mimetype="text/plain", status=206)
return Response(_read_log(log), mimetype="text/plain")
except FileNotFoundError:
return Response(f"Logfile {file_path} does not exist. "
f"Likely a crash during spinup of multiworld instance or it is still spinning up.",
mimetype="text/plain")
return "Access Denied", 403
@app.route('/room/<suuid:room>', methods=['GET', 'POST'])
@app.post("/room/<suuid:room>")
def host_room_command(room: UUID):
room: Room = Room.get(id=room)
if room is None:
return abort(404)
if room.owner == session["_id"]:
cmd = request.form["cmd"]
if cmd:
Command(room=room, commandtext=cmd)
commit()
return redirect(url_for("host_room", room=room.id))
@app.get("/room/<suuid:room>")
def host_room(room: UUID):
room: Room = Room.get(id=room)
if room is None:
return abort(404)
if request.method == "POST":
if room.owner == session["_id"]:
cmd = request.form["cmd"]
if cmd:
Command(room=room, commandtext=cmd)
commit()
return redirect(url_for("host_room", room=room.id))
now = datetime.datetime.utcnow()
# indicate that the page should reload to get the assigned port
should_refresh = not room.last_port and now - room.creation_time < datetime.timedelta(seconds=3)
should_refresh = ((not room.last_port and now - room.creation_time < datetime.timedelta(seconds=3))
or room.last_activity < now - datetime.timedelta(seconds=room.timeout))
with db_session:
room.last_activity = now # will trigger a spinup, if it's not already running
return render_template("hostRoom.html", room=room, should_refresh=should_refresh)
browser_tokens = "Mozilla", "Chrome", "Safari"
automated = ("update" in request.args
or "Discordbot" in request.user_agent.string
or not any(browser_token in request.user_agent.string for browser_token in browser_tokens))
def get_log(max_size: int = 0 if automated else 1024000) -> str:
if max_size == 0:
return ""
try:
with open(os.path.join("logs", str(room.id) + ".txt"), "rb") as log:
raw_size = 0
fragments: List[str] = []
for block in _read_log(log):
if raw_size + len(block) > max_size:
fragments.append("")
break
raw_size += len(block)
fragments.append(block.decode("utf-8"))
return "".join(fragments)
except FileNotFoundError:
return ""
return render_template("hostRoom.html", room=room, should_refresh=should_refresh, get_log=get_log)
@app.route('/favicon.ico')

View File

@ -3,6 +3,7 @@ import json
import os
from textwrap import dedent
from typing import Dict, Union
from docutils.core import publish_parts
import yaml
from flask import redirect, render_template, request, Response
@ -66,6 +67,22 @@ def filter_dedent(text: str) -> str:
return dedent(text).strip("\n ")
@app.template_filter("rst_to_html")
def filter_rst_to_html(text: str) -> str:
"""Converts reStructuredText (such as a Python docstring) to HTML."""
if text.startswith(" ") or text.startswith("\t"):
text = dedent(text)
elif "\n" in text:
lines = text.splitlines()
text = lines[0] + "\n" + dedent("\n".join(lines[1:]))
return publish_parts(text, writer_name='html', settings=None, settings_overrides={
'raw_enable': False,
'file_insertion_enabled': False,
'output_encoding': 'unicode'
})['body']
@app.template_test("ordered")
def test_ordered(obj):
return isinstance(obj, collections.abc.Sequence)
@ -214,6 +231,13 @@ def generate_yaml(game: str):
del options[key]
# Detect keys which end with -range, indicating a NamedRange with a possible custom value
elif key_parts[-1].endswith("-range"):
if options[key_parts[-1][:-6]] == "custom":
options[key_parts[-1][:-6]] = val
del options[key]
# Detect random-* keys and set their options accordingly
for key, val in options.copy().items():
if key.startswith("random-"):

View File

@ -1,10 +1,11 @@
flask>=3.0.3
werkzeug>=3.0.3
pony>=0.7.17
werkzeug>=3.0.6
pony>=0.7.19
waitress>=3.0.0
Flask-Caching>=2.3.0
Flask-Compress>=1.15
Flask-Limiter>=3.7.0
bokeh>=3.1.1; python_version <= '3.8'
bokeh>=3.4.1; python_version >= '3.9'
Flask-Limiter>=3.8.0
bokeh>=3.5.2
markupsafe>=2.1.5
Markdown>=3.7
mdx-breakless-lists>=1.0.1

View File

@ -8,7 +8,8 @@ from . import cache
def robots():
# If this host is not official, do not allow search engine crawling
if not app.config["ASSET_RIGHTS"]:
return app.send_static_file('robots.txt')
# filename changed in case the path is intercepted and served by an outside service
return app.send_static_file('robots_file.txt')
# Send 404 if the host has affirmed this to be the official WebHost
abort(404)

31
WebHostLib/session.py Normal file
View File

@ -0,0 +1,31 @@
from uuid import uuid4, UUID
from flask import session, render_template
from WebHostLib import app
@app.before_request
def register_session():
session.permanent = True # technically 31 days after the last visit
if not session.get("_id", None):
session["_id"] = uuid4() # uniquely identify each session without needing a login
@app.route('/session')
def show_session():
return render_template(
"session.html",
)
@app.route('/session/<string:_id>')
def set_session(_id: str):
new_id: UUID = UUID(_id, version=4)
old_id: UUID = session["_id"]
if old_id != new_id:
session["_id"] = new_id
return render_template(
"session.html",
old_id=old_id,
)

View File

@ -1,51 +0,0 @@
window.addEventListener('load', () => {
const tutorialWrapper = document.getElementById('faq-wrapper');
new Promise((resolve, reject) => {
const ajax = new XMLHttpRequest();
ajax.onreadystatechange = () => {
if (ajax.readyState !== 4) { return; }
if (ajax.status === 404) {
reject("Sorry, the tutorial is not available in that language yet.");
return;
}
if (ajax.status !== 200) {
reject("Something went wrong while loading the tutorial.");
return;
}
resolve(ajax.responseText);
};
ajax.open('GET', `${window.location.origin}/static/assets/faq/` +
`faq_${tutorialWrapper.getAttribute('data-lang')}.md`, true);
ajax.send();
}).then((results) => {
// Populate page with HTML generated from markdown
showdown.setOption('tables', true);
showdown.setOption('strikethrough', true);
showdown.setOption('literalMidWordUnderscores', true);
tutorialWrapper.innerHTML += (new showdown.Converter()).makeHtml(results);
adjustHeaderWidth();
// Reset the id of all header divs to something nicer
for (const header of document.querySelectorAll('h1, h2, h3, h4, h5, h6')) {
const headerId = header.innerText.replace(/\s+/g, '-').toLowerCase();
header.setAttribute('id', headerId);
header.addEventListener('click', () => {
window.location.hash = `#${headerId}`;
header.scrollIntoView();
});
}
// Manually scroll the user to the appropriate header if anchor navigation is used
document.fonts.ready.finally(() => {
if (window.location.hash) {
const scrollTarget = document.getElementById(window.location.hash.substring(1));
scrollTarget?.scrollIntoView();
}
});
}).catch((error) => {
console.error(error);
tutorialWrapper.innerHTML =
`<h2>This page is out of logic!</h2>
<h3>Click <a href="${window.location.origin}">here</a> to return to safety.</h3>`;
});
});

View File

@ -77,4 +77,4 @@ There, you will find examples of games in the `worlds` folder:
You may also find developer documentation in the `docs` folder:
[/docs Folder in Archipelago Code](https://github.com/ArchipelagoMW/Archipelago/tree/main/docs).
If you have more questions, feel free to ask in the **#archipelago-dev** channel on our Discord.
If you have more questions, feel free to ask in the **#ap-world-dev** channel on our Discord.

View File

@ -1,51 +0,0 @@
window.addEventListener('load', () => {
const tutorialWrapper = document.getElementById('glossary-wrapper');
new Promise((resolve, reject) => {
const ajax = new XMLHttpRequest();
ajax.onreadystatechange = () => {
if (ajax.readyState !== 4) { return; }
if (ajax.status === 404) {
reject("Sorry, the glossary page is not available in that language yet.");
return;
}
if (ajax.status !== 200) {
reject("Something went wrong while loading the glossary.");
return;
}
resolve(ajax.responseText);
};
ajax.open('GET', `${window.location.origin}/static/assets/faq/` +
`glossary_${tutorialWrapper.getAttribute('data-lang')}.md`, true);
ajax.send();
}).then((results) => {
// Populate page with HTML generated from markdown
showdown.setOption('tables', true);
showdown.setOption('strikethrough', true);
showdown.setOption('literalMidWordUnderscores', true);
tutorialWrapper.innerHTML += (new showdown.Converter()).makeHtml(results);
adjustHeaderWidth();
// Reset the id of all header divs to something nicer
for (const header of document.querySelectorAll('h1, h2, h3, h4, h5, h6')) {
const headerId = header.innerText.replace(/\s+/g, '-').toLowerCase();
header.setAttribute('id', headerId);
header.addEventListener('click', () => {
window.location.hash = `#${headerId}`;
header.scrollIntoView();
});
}
// Manually scroll the user to the appropriate header if anchor navigation is used
document.fonts.ready.finally(() => {
if (window.location.hash) {
const scrollTarget = document.getElementById(window.location.hash.substring(1));
scrollTarget?.scrollIntoView();
}
});
}).catch((error) => {
console.error(error);
tutorialWrapper.innerHTML =
`<h2>This page is out of logic!</h2>
<h3>Click <a href="${window.location.origin}">here</a> to return to safety.</h3>`;
});
});

View File

@ -288,6 +288,11 @@ const applyPresets = (presetName) => {
}
});
namedRangeSelect.value = trueValue;
// It is also possible for a preset to use an unnamed value. If this happens, set the dropdown to "Custom"
if (namedRangeSelect.selectedIndex == -1)
{
namedRangeSelect.value = "custom";
}
}
// Handle options whose presets are "random"

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Some files were not shown because too many files have changed in this diff Show More