Compare commits

...

1872 Commits

Author SHA1 Message Date
30fa0658b0 remove attestation from docker workflow
I don't know what this is or what value this adds, so removing it for now as it doesn't work on gitea
2026-02-23 19:04:15 -08:00
44a0c44036 update docker.yml to create and publish a docker image to dockerhub 2026-02-23 18:54:19 -08:00
Fabian Dill
d83da1b818 WebHost: memory leak fixes (#5966) 2026-02-22 21:22:22 +01:00
Mysteryem
0de09cd794 Core: Better scaling explicit indirect conditions (#4582)
* Core: Better scaling explicit indirect conditions

When the number of connections to retry was large and `queue` was large
`new_entrance not in queue` would get slow.

For the average supported world, the difference this change makes is
negligible.

For a game like Blasphemous, with a lot of explicit indirect conditions,
generation of 10 template Blasphemous yamls with
`--skip_output --seed 1` and progression balancing disabled went from
19.0s to 17.9s (5.9% reduction in generation duration).

* Create a new variable for the new set created from the intersection
2026-02-21 15:16:57 +01:00
Ixrec
48c201af19 Docs: Replace the 'true filler' weasel words in adding games.md's mention of get_filler_item_name() (#5958)
* replace the 'true filler' weasel words with a clear term defined by the linked method's docstring

* Update docs/adding games.md

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

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2026-02-20 21:43:34 +01:00
BroOtti
b0300d3063 Factorio: Update Download Image in guides (#5953) 2026-02-19 22:46:23 +01:00
Mysteryem
e0e34894a3 HK: Fix cached filler item names persisting between generations (#5950)
HK's `get_filler_item_name` was writing lists into a ClassVar[dict] on
the `HKWorld` class. This dict would not be cleaned out between
generations on the same process, leaving behind cached data from
previous generations.

I confirmed the issue when running single-slot generations on a local
webhost, where `self.cached_filler_items` could be already populated
during `HKWorld.__init__()`.

This has been fixed by putting an individual cache list on each HKWorld
instance, instead of a shared cached on the class.
2026-02-19 20:50:13 +01:00
Mysteryem
18e3a8911f Saving Princess: Fix each slot sharing the same music_table (#5952)
`music_table` was initialized on the `SavingPrincessWorld` *class*, so
was being shared by each Saving Princess slot in the multiworld.

This has been fixed by initializing the `music_table` attribute on each
`SavingPrincessWorld` *instance* in `generate_early()` instead.
2026-02-19 20:13:54 +01:00
Ian Robinson
c505b1c32c Core: Add missing args to rule builder inits (#5912)
* add filtered_resolution to inits

* update from_dict calls too
2026-02-18 22:40:16 +01:00
Silvris
e22e434258 Options: support "random" and variations for OptionSet with defined valid_keys (#4418)
* seemingly works? needs testing

* attempt docs update

* move to verify resolution (keep?)

* account for no valid keys and "random" being passed

* Update advanced_settings_en.md

* Update Options.py

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

* Update Options.py

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

* unify random handling between range and set

* Update Options.py

* Update Options.py

* Update Options.py

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

* super is weird

* fix item/location

* remove groups from options

* unittest

* pep8

* Update Options.py

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

* Update Options.py

---------

Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2026-02-18 21:16:04 +01:00
Ian Robinson
8b91f9ff72 Rule Builder: Make region.connect and add_event support rule builder (#5933)
* make region.connect and add_event support rule builder

* fix test

* oops fix

* update tests and typing

* rm unused
2026-02-18 20:57:05 +01:00
PoryGone
fadcfbdfea Celeste (Open World): v1.0.7 Logic Fixes (#5827)
### Logic Fixes:
- Old Site A
  - Logic now allows for going backwards from the `Awake` checkpoint
- Golden Ridge A
  - `Golden Strawberry` now requires `Moving Platforms` as it should
- Mirror Temple A
  - `Room b-01c Strawberry` and `Room b-10 Strawberry` no longer erroneously require `Red Boosters`
  - `Golden Strawberry` now requires `Dash Refills` as it should
- Reflection A
  - Logic now allows for going backwards from the `Reflection` checkpoint
- Reflection B
  - Logic now allows for going backwards from the `Reflection` checkpoint
- Farewell
  - `Power Source Key 2` now logically requires `Dash Switches` and `Double Dash Refills` as it should
2026-02-18 19:06:11 +01:00
qwint
3c4c294f9c WebHost: Better document config loading fallback (#5948)
* change functionality to follow comment

* revert code change and explicitly document intent
2026-02-18 17:51:58 +00:00
Silvris
27a7e538df Launcher: run init_logging before importing from worlds (#5402) 2026-02-15 23:48:53 +01:00
Katelyn Gigante
cb0cadcc5f core: If a user specifies --no-gui, don't show GUI messageboxes (#5514)
* move `gui_enabled` to Utils

* docstring

* If a user specified no-gui, don't use GUI messageboxes

---------

Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
2026-02-15 20:22:37 +01:00
black-sliver
2e1035a29f Doc: running from source and building on Linux (#5881)
* CI: make the comment in 'Build' more verbose

* Doc: add Linux running from source and build instructions

* Doc: fix name in running from source on Linux

* Update docs/running from source.md

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

---------

Co-authored-by: qwint <qwint.42@gmail.com>
2026-02-15 19:10:34 +00:00
Silvris
21c7f3cd92 Launcher: generate templates for option presets (#5062) 2026-02-15 19:22:40 +01:00
Louis M
13b6a5f4b2 Aquaria: Adding a lots of options and one check (#4414)
First, there is one check that has been added. The location is "Sitting on the throne before the cathedral with the crest on it" and the item is the "Opening of the Cathedral door". In Vanilla, sitting on the crested throne open the door to the cathedral.

Now for the options added:
- infinite_hot_soup: Make the game impossible to run out of hot soup once you got it as an item.
- open_body_tongue: The body level (the ending level) is blocked by a big tongue. This option remove the tongue without having to go to the Sunken City (where it is normally removed)
- maximum_ingredient_amount: In the Vanilla game, the ingredients and dishes count is limited to 8. This option make this count configurable.
- skip_final_boss_3rd_form: The final boss has 5 forms. The 3rd one is long and not really challenging. So, this option is used to skip this form.
- save_healing: Normally, the save points heal the player. There is also beds in the game that can heal the player. This option removed the healing from the save point and forced the player to heal using beds (or healing monsters or healing items)
- no_progression_(whatever): Make this "whatever" (generally regions) exempt of progression items. Note that this is not using the exclusion-feature of AP, as these locations may still contain 'Useful' items. It is only guaranteed that no 'Progression' and 'Progression_Skip_Balancing'-items will appear in these regions. This option does not remove locations. I did not exclude or completely remove the regions because I don't have enough location to put every useful item in the game.

There is also 2 new goals:
- Four gods: The goal is obtained when the player beat the four gods (this is something like half the game). Useful to have quicker runs
- Gods and Creator: Like the Four Gods run, but when the four gods are obtained, that open a transportation turtle to the final boss (the Creator) and the player have to beat the final boss to obtain the goal.

Note that for the 2 new goals, all locations from the last 4 areas (Abyss, Frozen Veil, Sunken City and The Body) are completely removed (not just excluded).
2026-02-15 19:20:45 +01:00
Fabian Dill
78e8082a6f CommonClient: actually close the UI on /exit (#5860) 2026-02-15 18:39:35 +01:00
agilbert1412
1de91fab67 Stardew Valley: 7.x.x - The Jojapocalypse Update (#5432)
Major Content update for Stardew Valley

### Features
- New BundleRandomization Value: Meme Bundles - Over 100 custom bundles, designed to be jokes, references, trolls, etc
- New Setting: Bundles Per Room modifier
- New Setting: Backpack Size
- New Setting: Secretsanity - Checks for triggering easter eggs and secrets
- New Setting: Moviesanity - Checks for watching movies and sharing snacks with Villagers
- New Setting: Eatsanity - Checks for eating items
- New Setting: Hatsanity - Checks for wearing Hats
- New Setting: Start Without - Allows you to select any combination of various "starting" items, that you will actually not start with. Notably, tools, backpack slots, Day5 unlocks, etc.
- New Setting: Allowed Filler Items - Allows you to customize the filler items you'll get
- New Setting: Endgame Locations - Checks for various expensive endgame tasks and purchases
- New Shipsanity value: Crops and Fish
- New Settings: Jojapocalypse and settings to customize it
- Bundle Plando: Replaced with BundleWhitelist and BundleBlacklist, for more customization freedom
- Added a couple of Host.yaml settings to help hosts allow or ban specific difficult settings that could cause problems if the people don't know what they are signing up for.

Plus a truckload of improvements on the mod side, not seen in this PR.

### Removed features
- Integration for Stardew Valley Expanded. It is simply disabled, the code is all still there, but I'm extremely tired of providing tech support for it, plus Stardew Valley 1.7 was announced and that will break it again, so I'm done. When a maintainer steps up, it can be re-enabled.
2026-02-15 18:02:21 +01:00
Scipio Wright
4ef5436559 TUNIC: Depriority for some items (#5589) 2026-02-15 17:47:40 +01:00
josephwhite
f2a6a769b0 Webhost: Fix defaults for NamedRange and TextChoice (#5139) 2026-02-15 17:46:40 +01:00
NewSoupVi
8a767bd2ad APQuest: Improve the auto-generated .gitignore for data/sounds (#5670)
I didn't quite think this through: In this specific case, you want the gitignore to also ignore itself, since it itself is an auto-generated file.
2026-02-14 00:35:12 +01:00
CodeGorilla
7df243b860 Utils: Improvements to visualize_regions for debugging GER usage (#4685)
* Improvements to visualize_regions for debugging GER usage

- allow the user to pass in a dict[int, int] to visualize_regions that maps Entrance.randomization_group to a color in RGB form. This allows for better visualization of which dangling entrances should match, or which matching groups are not being correctly respected.
- do full region visualization for unreached regions, so that entrances that could connect to new regions can be visualized.
- visualize unconnected entrances on regions, in addition to connected and unconnected exits, so that available ER targets can be visualized as well

* Add detail_disconnected_regions parameter to visualize_regions

* Rename detail_disconnected_regions to detail_other_regions for consistency

* Add auto_assign_colors param to visualize_regions

* Make auto assignment of entrance colors deterministic

* Assume show_other_regions is true if detail_other_regions is true

* Remove unused random import

* whitespace adjustments

* Move overflow check to prevent potential infinite loop

It wasn't exactly likely, as the user would have had to manually define all 4096 colors and then need an additional color on top of that, but accounting for that kind of nonsense is easy enough in this case.

* positive condition

---------

Co-authored-by: CodeGorilla <3672561+Ars-Ignis@users.noreply.github.com>
2026-02-08 18:39:49 +01:00
earthor1
f35d91933b Core: Throw OptionError for option type Toggle in certain scenarios (#5874)
* Throw OptionError for option type Toggle in certain scenarios

* Adding missing space to Options.py

Co-authored-by: Katelyn Gigante <clockwork.singularity@gmail.com>

---------

Co-authored-by: Katelyn Gigante <clockwork.singularity@gmail.com>
2026-02-08 18:34:12 +01:00
Ian Robinson
286769a0f3 Core: Add rule builder (#5048)
* initial commit of rules engine

* implement most of the stuff

* add docs and fill out rest of the functionality

* add in explain functions

* dedupe items and add more docs

* pr feedback and optimization updates

* Self is not in typing on 3.10

* fix test

* Update docs/rule builder.md

Co-authored-by: BadMagic100 <dempsey.sean@outlook.com>

* pr feedback

* love it when CI gives me different results than local

* add composition with bitwise and and or

* strongly typed option filtering

* skip resolving location parent region

* update docs

* update typing and add decorator

* add string explains

* move simplify code to world

* add wrapper rule

* I may need to abandon the generic typing

* missing space for faris

* fix hashing for resolved rules

* thank u typing extensions ilu

* remove bad cacheable check

* add decorator to assign hash and rule name

* more type crimes...

* region access rules are now cached

* break compatibility so new features work

* update docs

* replace decorators with __init_subclass__

* ok now the frozen dataclass is automatic

* one more type fix for the road

* small fixes and caching tests

* play nicer with tests

* ok actually fix the tests

* add item_mapping for faris

* add more state helpers as rules

* fix has from list rules

* fix can reach location caching and add set completion condition

* fix can reach entrance caching

* implement HasGroup and HasGroupUnique

* add more tests and fix some bugs

* Add name arg to create_entrance

Co-authored-by: roseasromeo <11944660+roseasromeo@users.noreply.github.com>

* fix json dumping option filters

* restructure and test serialization

* add prop to disable caching

* switch to __call__ and revert access_rule changes

* update docs and make edge cases match

* ruff has lured me into a false sense of security

* also unused

* fix disabling caching

* move filter function to filter class

* add more docs

* tests for explain functions

* Update docs/rule builder.md

Co-authored-by: roseasromeo <11944660+roseasromeo@users.noreply.github.com>

* chore: Strip out uses of TYPE_CHECKING as much as possible

* chore: add empty webworld for test

* chore: optimize rule evaluations

* remove getattr from hot code paths

* testing new cache flags

* only clear cache for rules cached as false in collect

* update test for new behaviour

* do not have rules inherit from each other

* update docs on caching

* fix name of attribute

* make explain messages more colorful

* fix issue with combining rules with different options

* add convenience functions for filtering

* use an operator with higher precedence

* name conflicts less with optionfilter

* move simplify and instance caching code

* update docs

* kill resolve_rule

* kill true_rule and false_rule

* move helpers to base classes

* update docs

* I really should finish all of my

* fix test

* rename mixin

* fix typos

* refactor rule builder into folder for better imports

* update docs

* do not dupe collectionrule

* docs review feedback

* missed a file

* remove rule_caching_enabled from base World

* update docs on caching

* shuffle around some docs

* use option instead of option.value

* add in operator and more testing

* rm World = object

* test fixes

* move cache to logic mixin

* keep test rule builder world out of global registry

* todone

* call register_dependencies automatically

* move register deps call to call_single

* add filtered_resolution

* allow bool opts on filters

* fix serialization tests

* allow reverse operations

---------

Co-authored-by: BadMagic100 <dempsey.sean@outlook.com>
Co-authored-by: roseasromeo <11944660+roseasromeo@users.noreply.github.com>
2026-02-08 17:00:23 +01:00
black-sliver
1dd91ec85b Core, Tests: allow Archipelago items in all worlds (#5893) 2026-02-05 08:56:25 +01:00
dependabot[bot]
6adeb8b95e SC2: Bump protobuf from 6.31.1 to 6.33.5 in /worlds/_sc2common (#5890)
Bumps [protobuf](https://github.com/protocolbuffers/protobuf) from 6.31.1 to 6.33.5.
- [Release notes](https://github.com/protocolbuffers/protobuf/releases)
- [Commits](https://github.com/protocolbuffers/protobuf/commits)

---
updated-dependencies:
- dependency-name: protobuf
  dependency-version: 6.33.5
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-05 07:37:09 +01:00
ScorelessPine
3e0d42bf9e Core: Add SDL_MOUSE_FOCUS_CLICKTHROUGH=1 environment variable to kvui (#5804)
This variable should fix the 'double click' required when trying to interact with buttons on an unfocused window
2026-02-05 01:32:25 +01:00
James White
41e22dabda KH2: Add SuperBosses, Cups, AtlanticaToggle and SummonLevelLocationToggle to slot data (#5708)
* Add SuperBosses, Cups and AtlanticaToggle

* Add SummonLevelLocationToggle
2026-02-05 01:14:35 +01:00
PIEisFANTASTIC
39e7ee315e KH2: Add a new "CasualBounties" Setting (#4877)
* KH2: casual bounties option

* Casual Bounty: Adjust level bounty logic to correspond with max level check setting

* Bugfix: We have one less possible bounty with corresponding level bounty logic

* Casual Bounty: Move option to better spot

* Bugfix: Prevent possible .remove() crash

* Revert "Bugfix: We have one less possible bounty with corresponding level bounty logic"

This reverts commit 3c929e00db.

* Bugfix: Typo in conditional

* Casual Bounties: Remove Scar, add MCP

I knew I was missing one second visit fight and Scar shouldn't be there he's a first visit

* Casual Bounties: Add some clarity to the CasualBounty setting

* Docs: Update docs to reflect new CasualBounty setting

* KH2: Add bounty locations as location groups

Feedback on this needed, trying to do this to make it work with the code above the additions made it so the game generated 1 less item than locations, despite linking properly
It does function as intended though

* KH2: Update docs
2026-02-05 01:11:40 +01:00
jamesbrq
3e032e6cd6 MLSS: Add Manifest + Minor Bugfixes (#5728)
* Remove outdated header change for ROM verification

* Update Connections to be compatible with python ver. 3.8

* Update inno_setup.iss

* Update inno_setup.iss

* Merge branch 'main' of https://github.com/jamesbrq/ArchipelagoMainMLSS

* Add Manifest + Minor Bugfixes

* Even further safeguards for Oho Oasis Temples

* Update basepatch.bsdiff
2026-02-05 00:58:34 +01:00
mechanicset
609f4af600 Satisfactory: Update Universal Tracker Method for FinalElevatorPhase Option (#5812) 2026-02-05 00:44:40 +01:00
Jonathan Tan
4c27e35445 TWW: Support launcher command line arguments (#5806)
* Support launcher command line arguments

* Use `launch` instead of `launch_subprocess`

* Remove old runner code
2026-02-05 00:41:48 +01:00
soopercool101
b0c967c039 Docs, SM64: Remove outdated FAQ item (#5887)
It is no longer possible to connect to a multiworld game on a version of the client with this bug, as all versions with this bug report AP v0.3.5 or less
2026-02-05 00:36:26 +01:00
GreenMarco
c51da00bfb Docs: add spanish language for MLSS (#5172)
* Docs: add spanish language for SM64

* Docs: add spanish language for MLSS

* Update worlds/mlss/docs/setup_es.md

Co-authored-by: PantoUwUr <99690102+PantoUwUr@users.noreply.github.com>

* Update worlds/mlss/docs/es_Mario & Luigi Superstar Saga.md

Co-authored-by: RoobyRoo <thegreenrobby@gmail.com>

---------

Co-authored-by: PantoUwUr <99690102+PantoUwUr@users.noreply.github.com>
Co-authored-by: RoobyRoo <thegreenrobby@gmail.com>
2026-02-05 00:26:56 +01:00
massimilianodelliubaldini
f3389f5d8b Jak and Daxter: Replace Pymem, Add Linux Support (#5850)
* Replace pymem with PyMemoryEditor (nonworking)

* Add back pymem for faster windows address searching.

* Replace other uses of pymem, parameterize executable names.

* Updated to add linux and potential MacOS support to launching gk and … (#84)

* Updated to add linux and potential MacOS support to launching gk and goalc. Still needs tested on MacOS.

* Switched to using x-terminal-emulator instead of trying to find gnome-terminal or konsole

Made argument building for suprocessing goalc easier to read

Fixed OS X support to use osascript instead of attempting to run Terminal directly

* Changed Terminal usage to use Archipelago's Launh utility, which handles terminal launching for me for both linux and OS X

* Added try/except to re-connect the memory process. The process file/id changes over time on linux, and this works to re-connect without needing to restart

* Removed Unsetting  env var in favor of reporting to the source authors

* Putting PyMemoryEditor local. (#85)

* Putting PyMemoryEditor local

---------

Co-authored-by: massimilianodelliubaldini <8584296+massimilianodelliubaldini@users.noreply.github.com>

* Fixing minor problems (#87)

* Refactor away circular launcher import.

* Push latest PyMemoryEditor scan utility (#91)

Co-authored-by: Louis M <Louis M>

* Remove Pymem, rely solely on PyMemoryEditor. Add konsole support.

* Jak 1: Remove vendored copy of PME, update imports, requirements, and manifest.

* Jak 1: Prevent server connect until game is properly setup.

* Jak 1: reduce REPL/Compiler confusion, small updates to setup guide.

* Write hack for Konsole on AppImage to avoid OpenSSL error.

* Refactor LD_LIBRARY_PATH hack.

* Update worlds/jakanddaxter/agents/memory_reader.py

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

* Update worlds/jakanddaxter/agents/memory_reader.py

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

---------

Co-authored-by: Morgan <morgan07kelley@gmail.com>
Co-authored-by: Louis M <prog@tioui.com>
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2026-02-04 18:45:09 +01:00
Duck
3b1971be66 Core: Fix some typing errors (#4995)
* Fix some type errors in Generate and Options

* Add type parameter to new hint and fix whitespace errors

* Update identifier style
2026-02-02 19:55:57 +01:00
black-sliver
4cb518930c Fix, OptionsCreator: export options on Linux (#5774)
* Core/Utils: Use correct env for save_filename from AppImage

* OptionsCreator: run export on a separate thread

Running a blocking call from kivy misbehaves on Linux.
This also changes '*.yaml' to '.yaml' for Utils.save_filename,
which is the correct way to call it.

* Core/Utils: destroy Tk root after save/open_filename

This allows using those functions from multiple threads.
Note that pure Tk apps should not use those functions from Utils.

* OptionsCreator: show snack when save_filename fails

* OptionsCreator: disable window while exporting

* OptionsCreator: fixing typing of added stuff
2026-02-01 22:23:14 +01:00
Omnises Nihilis
c835bff570 Docs: KH1 more troubleshooting and clearer nomenclature (#5872)
* updated kh1 docs

* second pass

* tweak

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Flit <8645405+FlitPix@users.noreply.github.com>

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Flit <8645405+FlitPix@users.noreply.github.com>

* Update worlds/kh1/docs/kh1_en.md

Co-authored-by: Flit <8645405+FlitPix@users.noreply.github.com>

* semicolon

---------

Co-authored-by: Flit <8645405+FlitPix@users.noreply.github.com>
2026-02-01 18:22:28 +01:00
Natalie Weizenbaum
6ee02fc62d Docs (DS3): Fix the documentation for the Simple Early Bosses option (#5856)
* Docs (DS3): Fix the documentation for the Simple Early Bosses option

This option changed in the client a while ago, but we forgot to update
the server.

* Update Options.py
2026-02-01 12:06:16 +01:00
Jacob Lewis
8095f922bc [WebHost Docs] Updated and clarified new tracker endpoitns and misc fixes. (#5475)
* Adding json/python to codeblocks to make it pretty, fixed spelling mistakes, swapped uuids for suuids in the examples, and expanded on /tracker and /static_tracker, and /slot_data_tracker giving the details of the API calls endpoints

* Add in API Cacheing timers and related text blurb

* updated for merged edit to /static_tracker

* Removed timer from /datapackage/checksum
2026-01-31 20:19:46 +01:00
CookieCat
77e5f3733e AHIT: Add option to shuffle Battle of the Birds director tokens and time bonus pickups (#5400) 2026-01-31 20:09:31 +01:00
Rosalie
c47687dd21 TLOZ: Move completion condition to be before set_rules is complete (#5391) 2026-01-31 20:08:40 +01:00
Exempt-Medic
8662433142 FFMQ: Fix Collect/Remove Asymmetry (#5253) 2026-01-31 20:05:43 +01:00
PlatanoBailando
5f073c2a76 Doc: Reword required python version for AP (#5822)
Many many people have read this and then installed 3.14, so it clearly needs rewording.
2026-01-31 13:49:54 +01:00
Duck
c5d67dd97a Docs: Explain building a single world with Build APWorlds component (#5879) 2026-01-31 13:30:59 +01:00
black-sliver
9b421450b1 Doc: WebHost: update readme and style guide (#4853)
* Doc: WebHost living standard

* Docs: update style guide for HTML, CSS and JS

* Unblame phar

* Too many words

* The better choice

* More rules

* Removed too much

* Docs: add recommendations for script defer and async
2026-01-28 20:57:12 +01:00
JaredWeakStrike
a6740e7be3 KH2: Deathlink and ingame item popups (#5206)
---------

Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: Delilah <lindsaydiane@gmail.com>
2026-01-28 07:10:29 +01:00
Duck
65ef35f1b4 Core: Give clearer error message for invalid .apworld zip (#5871)
* Update messages and check

* Make "official" error message show up for 3.14

* Add zip error handling

* Small cleanups
2026-01-27 22:48:50 +01:00
Duck
520253e762 ModuleUpdate: Add explicit error when above max supported version (#5868)
* Update messages and check

* Make "official" error message show up for 3.14
2026-01-26 18:36:41 +00:00
threeandthreee
aa3614a32b LADX: fix improved additional warps (#5858) 2026-01-23 07:48:33 +01:00
Will Morrow
94492c45cb Super Mario 64: Add painting passability as items (#5294) 2026-01-21 15:12:53 +01:00
NewSoupVi
8f261bb27c Core: Add Pymem to requirements.txt (#5855)
As to not break custom worlds when Jak & Daxter moves from PyMem to PyMemoryEditor
2026-01-20 21:37:17 +01:00
Nicholas Saylor
ddd08342c8 Docs: Show that Data is optional for bounces #5794 2026-01-20 20:24:30 +01:00
Ixrec
c7db213ee9 Docs: explicitly document why get_filler_item_name may return non-IC.filler items, despite its name (#5747)
* Docs: explicitly document why get_filler_item_name may return non-IC.filler items, despite its name

* reword

* apply Scipio's rewordings

* Update worlds/AutoWorld.py

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

* any

---------

Co-authored-by: qwint <qwint.42@gmail.com>
2026-01-20 20:18:18 +01:00
Ixrec
220248dd3d Docs: define and explain the trade-off of "local" vs "remote" items (#5718)
* first draft

* second draft

* fix indentation of bullet point wrapped lines

* move quote

* explicitly discuss all three item handling flags, since the start inventory one is easily forgotten

* rewrite to avoid a 'debate between two camps' framing

* tweak the wording to allow for the possibility that some games can 'just' do both local and remote items without exposing this detail to the player

* relative links
2026-01-20 20:15:00 +01:00
Ixrec
5932160f15 Docs: add dev FAQ for 'should I start with the APWorld or the client?' (#5716)
* Docs: add dev FAQ for 'should I start with the APWorld or the client?'

* fix indentation of bullet point wrapped lines

* use %20 for spaces in links

* link to adding games.md and add #ap-modding-help to adding games.md

* make APQuest a link

* also linkify 'run a local server'

* reword the 'judging client is easier' point to reflect a broader range of first-timers

* move the 'not 100%' point into the introductory sentences, and tweak related wording

* correct link
2026-01-20 20:14:43 +01:00
black-sliver
76e0619b79 Core: Bump version from 0.6.6 to 0.6.7 (#5851) 2026-01-20 00:06:57 +01:00
Fabian Dill
646a52a2e7 LADX: no pickle (#5849) 2026-01-19 21:28:25 +01:00
NewSoupVi
e1322df8b0 APQuest: Explain game_name and supports_uri more in components.py (#5759)
* APQuest: Explain game_name and supports_uri more in components.py

Hopefully this can lead to more games implementing support for the "click on slot name -> everything launches automatically" functionality.

* Update components.py

* Update components.py
2026-01-19 21:26:20 +01:00
Doug Hoskisson
092a9dc6bd Core: fix bug with missing help text (#5632)
Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>
2026-01-19 20:13:43 +01:00
Phaneros
9f71fe707f SC2: fix supreme logic hole (#5768)
* sc2: Fixing a discrepancy between slot data and logic
where story tech would not be granted for supreme if zerg was not a selected race.

* sc2: Fixed an issue where Kinetic Blast was not listed as a vanilla Kerrigan ability

* sc2: Fixing some functions that could force Kerrigan items into the pool when playing Kerriganless

* sc2: excluding zerg excludes hots for vanilla-like mission order
* Preprocessing options
* Moving general empty selection handling to option preprocessing
* Adding a unit test for empty race/campaign selection

* sc2: Properly handling non-raceswapped campaigns when excluding campaigns based on race exclusions

* sc2: Adding an explicit error message if a user excludes all missions in a way with no obvious resolution
2026-01-19 20:11:31 +01:00
wildham
b8311a62e7 FFMQ: Update link to upstream rando (#5838) 2026-01-19 20:10:00 +01:00
Colin
13830ff4cb Timespinner: Align Lantern Logic (#5562) 2026-01-19 03:44:26 +01:00
Duck
c1b858b2cf Core: Add .apignore format to not include files in APWorld Builder (#5779) 2026-01-18 17:45:12 +01:00
Mysteryem
a035ac579c Noita: Fix filling Shop Item locations without updating item.location (#5840)
In single-player multiworlds with small item pools, Noita was manually
placing some items into Shop Item locations, but was only setting
location.item, and not also setting item.location so that the item and
location refer to one another.

This has been fixed by using the MultiWorld.push_item() helper method to
place the items instead of manually placing the items.
2026-01-18 14:47:55 +01:00
Duck
20c10e33c4 Shapez: Change image links to relative (#5803) 2026-01-18 14:46:51 +01:00
Duck
a4e4ce1c72 Core: Change image link to relative (#5802) 2026-01-18 14:45:41 +01:00
Scipio Wright
983936af8c TUNIC: Fix region for the grass by the West Garden portal (#5784) 2026-01-18 14:44:32 +01:00
Scrungip
62dfeac441 Super Mario Land 2: Fix Goal Logic (#5781) 2026-01-18 14:43:30 +01:00
Mysteryem
b81e1a228a The Messenger: Fix lambda capture issue in add_closed_portal_reqs (#5816) 2026-01-18 14:42:50 +01:00
lepideble
5899920e48 Factorio: fix inverted condition in victory requirements (#5647) 2026-01-18 14:33:52 +01:00
black-sliver
8dee460397 customserver: don't set last_activity that will be overwritten later (#5844) 2026-01-17 13:46:20 +01:00
Remy Jette
cda54e0bea WebHost: Fix world sorting in /tutorial/ (#5785) 2026-01-15 22:21:44 +01:00
Rob B
0554bf4e2d Satisfactory: Fix typo in GoalSelection possible values description comment (#5826) 2026-01-15 22:20:09 +01:00
Mysteryem
b92803e77f Core: replace the eval in OptionsCreator.py (#5828) 2026-01-15 22:19:13 +01:00
James White
69e83071ff Multiserver: remove dead code (#5831) 2026-01-11 16:54:12 +01:00
Benny D
875765e6dc PyCharm: Fix name of apworld builder run config (#5824)
* rename the apworld builder run config

* Update Build APWorlds.run.xml

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2026-01-09 10:24:37 +01:00
NewSoupVi
db56e26df9 Core: Make .apworlds importable using importlib (without force-importing them first) (#5734)
* Make apworlds importable in general

* move it to a probably more appropriate place?

* oops
2026-01-05 22:54:02 +01:00
Duck
5a88641228 Docs: Make image path in contributing absolute (#5790) 2025-12-25 12:59:32 +01:00
Ian Robinson
16559e7595 Core: allow abstract world classes (#5468) 2025-12-24 14:48:05 +01:00
NewSoupVi
d594d5d4a7 APQuest: Fix import shadowing issue (#5769)
* Fix import shadowing issue

* another comment
2025-12-22 15:32:52 +01:00
MarioManTAW
e950a2fa58 Paint: Add manifest (#5778)
* Paint: Implement New Game

* Add docstring

* Remove unnecessary self.multiworld references

* Implement start_inventory_from_pool

* Convert logic to use LogicMixin

* Add location_exists_with_options function to deduplicate code

* Simplify starting tool creation

* Add Paint to supported games list

* Increment version to 0.4.1

* Update docs to include color selection features

* Fix world attribute definitions

* Fix linting errors

* De-duplicate lists of traps

* Move LogicMixin to __init__.py

* 0.5.0 features - adjustable canvas size increment, updated similarity metric

* Fix OptionError formatting

* Create OptionError when generating single-player game with error-prone settings

* Increment version to 0.5.1

* Update CODEOWNERS

* Update documentation for 0.5.2 client changes

* Simplify region creation

* Add comments describing logic

* Remove unnecessary f-strings

* Remove unused import

* Refactor rules to location class

* Remove unnecessary self.multiworld references

* Update logic to correctly match client-side item caps

* Paint: Add manifest

---------

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2025-12-22 04:08:52 +01:00
Ixrec
1df38cb782 Docs: explicitly document why 2^53-1 is the max size, not ^31 or ^63 (#5717)
* explicitly document why 2^53-1 is the max size, not ^31 or ^63

* explicitly recommend 32-bit ids

* make description correct by explicitly mentioning and linking to a description of 'safe'
2025-12-20 23:19:42 +01:00
Benjamin S Wolf
c6400b6673 Core: Process all player files before reporting errors (#4039)
* Process all player files before reporting errors

Full tracebacks will still be in the console and in the logs, but this creates a relatively compact summary at the bottom.

* Include full typename in output

* Update module access and address style comments

* Annotate variables

* multi-errors: Revert to while loop

* Core: Handle each roll in its own try-catch

* multi-errors: Updated style and comments

* Undo accidental index change

* multi-errors: fix last remaining ref to erargs
2025-12-20 23:06:32 +01:00
Mysteryem
dbf2325c01 KH2: Fix placing single items onto multiple locations in pre_fill (#5619)
`goofy_pre_fill` and `donald_pre_fill` would pick a random `Item` from a
`list[Item]` and then use `list.remove()` to remove the picked `Item`,
but the lists (at least `donald_weapon_abilities`) could contain
multiple items with the same name, so `list.remove()` could remove a
different `Item` to the picked `Item`, allowing an `Item` in the list to
be picked and placed more than once.

This happens because `Item.__eq__` only compares the item's `.name` and
`.player`, and `list.remove()` compares by equality, meaning it can
remove a different, but equal, instance from the list.

This results in `old_location.item` not being cleared, so
`old_location.item` and `new_location.item` would refer to the same
item.
2025-12-20 22:32:12 +01:00
PinkSwitch
dd5b25399a Yoshi's Island - Fix some small logic issues that were reported, add json file (#5742)
* Fix Piece of Luigi not goaling until reset

* Update .gitignore

* fix logic thing that one guy said

* fix platform being missing from chomp rock zone rules

* add json file

* added the wrong one

* remove extraneous lnk

* Update archipelago.json

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-12-20 13:36:20 +01:00
Mysteryem
8178ee4e58 Satisfactory: Fix nondeterministic creation of trap filler items (#5766)
The `trap_selection_override` option is an `OptionSet` subclass, so its `.value` is a `set`.

Sets have nondeterministic iteration order (the iteration order depends on the hashes of the objects within the set, which can change depending on the random hashseed of the Python process).

This `.enabled_traps` is used in `Items.get_filler_item_name()` with `random.choice(self.enabled_traps)`, which is called as part of creating the item pool in `Items.build_item_pool()` (for clarity, this `random` is the world's `Random` instance passed as an argument, so no problems there). So, with `self.enabled_traps` being in a nondeterministic order, the picked trap to add to the item pool through `random.choice(self.enabled_traps)` would be nondeterministic.

Sorting the `trap_selection_override.value` before converting to a `tuple` ensures that the names in `.enabled_traps` are always in a deterministic order.

This issue was identified by merging the main branch into the PR branch for https://github.com/ArchipelagoMW/Archipelago/pull/4410 and seeing Satisfactory fail the tests for hash-determinism. With this fix applied, the tests in that PR pass.
2025-12-19 23:25:20 +01:00
Jarno
ad1b41ea81 Satisfactory/Timespinner: Added Manifesto (#5764)
* Added Manifesto

* Update archipelago.json

* Update archipelago.json

* Update archipelago.json

---------

Co-authored-by: Jarno <jarno.westhof@gmail.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-12-19 21:00:36 +01:00
Jarno
efd8528db0 MultiServer: Safe DataStorage .pop (#5060)
* Make datastorage .pop not throw on missing key or index

* Reworked to use logic rather than exception catching
2025-12-19 14:57:10 +01:00
Silvris
e54a15978f Celeste Open World: speedup module load (#5448)
* speedup world load

* those 3 weren't in-fact needed
2025-12-19 14:54:41 +01:00
Duck
d78b9ded2d Core: Add datapackage exports to gitignore (#5719)
* Gitignore and description

* Update description
2025-12-19 14:53:56 +01:00
Duck
53e8130c9c Yugioh: Add space in concatenated string (#5695)
* Add spaces

* Revert wrong one

* Add right one
2025-12-19 14:53:24 +01:00
PinkSwitch
55c70a5ba8 EarthBound: Implement New Game (#5159)
* Add the world

* doc update

* docs

* Fix Blast/Missile not clearing Reflect

* Update worlds/earthbound/__init__.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/__init__.py

remove unused import

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/__init__.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/modules/dungeon_er.py

make bool optional

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/modules/boss_shuffle.py

typing update

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/modules/boss_shuffle.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Filter events out of item name to id

* we call it a glorp

* Update worlds/earthbound/Regions.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/__init__.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/Items.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/earthbound/Regions.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Fix missing optional import

* hint stuff

* -Fix Apple Kid text being wrong
-Fix Slimy Pile text being wrong

* -Fix some sprite corruption if PSI was used when an enemy loaded another enemy
-Fixed a visible artifact tile during some cutscenes

* Update ver

* Update docs

* Fix some money scripting issues

* Add argument to PSI fakeout attack

* Updated monkey caves shop description

* Remove closing markdown from doc

* Add new flavors

* Make flavors actually work

* Update platforms

* Fix common gear getting duplicated

* Split region initialization

* Condense checks for start inventory + some other junk

* Fix some item groups - change receiver phone to warp pad

* wow that one was really bad :glorp:

* blah

* Fix cutoff option text

* switch start inventory concatenation to itertools

* Fix sky runner scripting bug - added some new comm suggestions

* Fix crash when generating with spoiler_only

* Fix happy-happy teleport not unlocking after beating carpainter

* Hint man hints can now use CreateHint packets to create hints in other games

* Adjust some filler rarity

* Update world to use CreateHints and deprecate old method

* Fix epilogue skip being offset

* Rearrange a couple regions

* Fix tendapants getting deleted in battle

* update doc

* i got scared and forgot i had multiple none checks and am worried about this triggering but tested and it works

* Fix mostly typing errors from silvris

* More type checks

* More typing

* Typema

* Type

* Fix enemy levels overwriting music

* Fix gihugic blunder

* Fix Lumine Hall enabling OSS

* del world

* Rel 4.2.7

* Remove some debug logs

* Fix vanilla bug with weird ambush detection

* Fix Starman Junior having an unscaled Freeze

* Change shop scaling

* Fix shops using the wrong thankful script

* Update some bosses in boss shuffle

* Loc group adjustment

* Update some boss shuffle stuff | Fix Enemizer attacks getting overwritten by Shuffle data | Fix flunkies not updating and still being used with enemizer

* Get rid of some debug stuff

* Get boss shuffle running, dont merge

* Fix json and get boss shuffle no plando back up

* Fix Magicant Boost not initializing to Ness if party count = 4

* Fix belch shop using wrong logic

* Don't re-send goal status

* EBitem

* remove :

* idk if this is whatvi wanted

* All client messagesnow only send when relevant instead of constantly

* Patch up the rest of boss plando

* Fix Giygas being not excluded from enemizer

* Fix epilogue again

* adjust the sphere scaling name

* add the things

* Fix Ness being placed onto monotoli when monotoli was in sea of eden

* Fix prefill properly

* Fix boss shuffle on vanilla slots.

* rename this, apparently

* Update archipelago.json

---------

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-12-19 14:52:27 +01:00
Jarno
ebbdd7bfda Satisfactory: Add New Game (#5190)
* Added Satisfactory to latest master

* Fixed hard drive from containing the mam + incremented default value for harddrive progression

* Apply cherry pick of 3076259

* Apply cherry pick of 6114a55

* Clarify Point goal behavior (https://github.com/Jarno458/SatisfactoryArchipelagoMod/issues/98)

* Update Setup guide and info page

* Add links to Gifting and Energy Link compatible games. Add info on Hard Drive behavior

* Fix typos

* Update hard drive behavior description

* Hopefully fixed the mam from getting placed behind harddrives

* Add 1 "Bundle: Solid Biofuel" to default starting items (for later chainsaw usage or early power gen)

* Add info/warning about save setup failure bug

* Add notes about dedicated server setup

* Fixes: `TypeError: 'set' object is not subscriptable`

random.choice does not work over set objects, cast to a list to allow 'trap_selection_override'

* progrees i think

* Fixed some bugs

* Progress commmit incase my pc crashes

* progress i think as test passed

* I guess test pass, game still unbeatable tho

* its generating

* Some refactorings

* Fixed generation with different elevator tiers

* Remove debug statement

* Fix this link.

* Implemented abstract base classes + some fixes

* Implemented many many new options

* Yay more stuff

* Fixed renaming of filters

* Added 1.1 stuffs

* Added options groups and presets

* Fixes after variable renmame

* Added recipy groups for easyer hinting

* Implemented random Tier 0

* Updated slot_data

* Latest update for 1.1

* Applied cheaper building costs of assembler and foundry

* Implemented exploration cost in slot_data

* Fixed exposing option type

* Add goal time estimates

* Trap info

* Added support for Universal Tracker
Put more things in the never exclude pool for a more familiar gameplay

* Added iron ore to build hub

* Added Dark Matter Crystals

* Added Single Dark Matter Crystals

* Fixed typo in options preset

* Update setup directions and info

* Options formatting fixes, lower minimum ExplorationCollectableCount, add new Explorer starting inventory items preset

* Fixed incorrect description on the options

* Reduce Portable Miner and Reinforced Iron Plate quantities in "Skip Tutorial Inspired" starting preset

* Fixed options pickling error

* Reworked logic to no longer include Single: items as filler
Reworked logic for more performance
Reworked logic to always put useful equipment in pool

* Fixed Itemlinks
Removed space elevator parts from fillers
Removed more AWESOME shop purchaseables from minimal item pool
Added all equipment to minimal item pool
Removed non fissile and fertile uranium from minimal item pool
Removed portal from minimal item pool
Removed Ionized fuel from minimal item pool
Removed recipes for Hoverpack and Turbo Rifle Ammo from minimal item pool
Lowered the chance for rolling steel on randomized starter recipes

* Fixed hub milestone item leaking to into wrong milestones

* Fixed unlock cost of geothermal generator

* Fixed itemlinks again

* Add troubleshooting note about hoverpacks

* Add starting inventory bundle delivery info

* Added hint generation at generation time
Harddrive locations now go from 1-100 rather then 0-99

* Update __init__.py

Fixed mistake

* Cleaned docs to be better suited to get verified

* Update CODEOWNERS

Added Satisfactory

* Update README.md

Added Satisfactory

* Restructure and expand setup page to instruct both players and hosts

* Add terms entry for Archipelago mod

* Fixed generation of traps

* Added Robb as code owner

* Restore tests to original state

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix additional typos from code review

* Implemented fix for itterating enum flags on python 3.10

* Update en_Satisfactory.md

* Update setup_en.md

* Apply suggestions from code review

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

* more world > multiworld

* Clarify universal tracker behavior

* Fix typos

* Info on smart hinting system

* Move list of additional mods to a page on the mod GitHub

* Restore revamped setup guide that other commits  overwrote
Originally from be26511205, d8bd1aaf04

* Removed bundle of ficsit coupons from the from the item pool
added estimated completion times to space elevator option description

* Apply suggestions from code review

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

* Wording

* Fix typo

* Update with changes from ToBeVerified branch

* Update note about gameplay options

* Update note about gameplay options

* Improved universal tracker handling

* Improved universal tracker + modernized code a bit

* Fixed bugs that where re-introduced

* Added Recipe: Excited Photonic Matter

* Removed python 3.9 workaround

* Fixed

* Apply suggestions from code review

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

* Streamlined handle craftable logic by using itterable rather then tuple
Removed dict.keys as the dict itzelf already enumerates over keys

* Updated option description

* Fixed typing

* More info on goal completion conditions

* More info on goal completion conditions (093fe38b6e)

* Apply suggestions from code review

Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>

* Implemented review results

* PEP8 stuff

* More PEP8

* Rename ElevatorTier->ElevatorPhase and related for clarity and consistency.
Untested

* speedups part1

* speedsups on part rules

* Fix formatting

* fix `Elevator Tier #` string literals missed in rename

* Remove unused/duplicate imports + organize imports, `== None` to `is None`

* Fixed after merge

* Updated values + removed TODO

* PEPed up the code

* Small refactorings

* Updated name slot data to phase

* Fix hint creation

* Clarify wording of elevator goal

* Review result

* Fixed minor typo in option

* Update option time estimates

---------

Co-authored-by: Rob B <computerguy440+gh@gmail.com>
Co-authored-by: ProverbialPennance <36955346+ProverbialPennance@users.noreply.github.com>
Co-authored-by: Joe Amenta <airbreather@linux.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-12-19 14:48:03 +01:00
Silent
863f161466 TUNIC: Update wording on Mask and Lantern option descriptions #5760 2025-12-19 14:42:05 +01:00
Silent
9305ecb3bc TUNIC: Update world version to 4.2.7 #5761 2025-12-19 14:41:37 +01:00
Scipio Wright
0002bb8e5a TUNIC: Make UT care about hex goal amount #5762 2025-12-19 14:11:29 +01:00
Alchav
b42fb77451 Factorio: Craftsanity (#5529) 2025-12-18 07:52:15 +01:00
Ziktofel
5a8e166289 SC2: New maintainership (#5752)
I (Ziktofel) stepped down but will remain as a mentor
2025-12-18 00:06:49 +01:00
Rosalie
5fa719143c TLOZ: Add manifest file (#5755)
* Added manifest file.

* Update archipelago.json

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-12-18 00:06:06 +01:00
Duck
a906f139c3 APQuest: Fix ValueError on typing numbers/backspace #5757 2025-12-18 00:02:11 +01:00
Katelyn Gigante
56363ea7e7 OptionsCreator: Respect World.hidden flag (#5754) 2025-12-17 20:09:35 +01:00
Fabian Dill
01e1e1fe11 WebHost: increase form upload limit (#5756) 2025-12-17 19:12:10 +01:00
Fabian Dill
4477dc7a66 Core: Bump version from 0.6.5 to 0.6.6 (#5753) 2025-12-17 03:33:29 +01:00
Silvris
45994e344e Tests: test that every option in a preset is visible in either simple or complex UI (#5750) 2025-12-16 19:27:02 +01:00
Silvris
51d5e1afae Launcher: fix shortcuts on the AppImage (#5726)
* fix appimage executable reference

* adjust working dir

* use argv0 instead of appimage directly

* set noexe on frozen
2025-12-15 03:30:07 +01:00
Ziktofel
577b958c4d SC2: Fix Kerrigan logic for active spells (#5746) 2025-12-15 00:56:54 +01:00
Benny D
ce38d8ced6 Docs: Add 'silasary' to Mac tutorial contributors (#5745) 2025-12-14 17:01:32 +01:00
BeeFox-sys
d65fcf286d Launcher: Add workaround for kivy bug for linux touchpad devices (#5737)
* add code to fix touchpad on linux, courtesy of Snu of the kivy community

* Launcher: Update workaround to follow styleguide
2025-12-12 02:44:22 +01:00
Phaneros
5a6a0b37d6 sc2: Fixing typos in item descriptions (#5739) 2025-12-11 22:43:06 +01:00
Fabian Dill
4a0a65d604 WebHost: add played game to static tracker (#5731) 2025-12-09 00:45:02 +01:00
Emily
d25abfc305 Docs: update apsudoku docs / add links to web build (#5720) 2025-12-05 01:09:56 +01:00
Duck
0905e3ce32 WebHost/Game Guides: Change links to stay on current instance (#5699)
* Remove absolute links to archipelago.gg

* Fix other link issues
2025-12-02 00:40:05 +01:00
black-sliver
ac84b272c5 CI: update appimage runtime to fix problems with sleep (#5706)
also updates appimagetool.
Old tool should be compatible, but there are 2 bug fixes in it.
2025-12-01 01:25:06 +01:00
Phaneros
e8a63abfa4 weights: Fixing negatives and zeroes disappearing from option dicts updated by triggers (#5677) 2025-11-30 13:36:36 +01:00
Silvris
3fa2745c37 OptionCreator: pre-RC1 fixes (#5680)
* fix str default on text choice

* fix range with default random

* forgot module update

* handle namedrange default special

* handle option group of options we should not render

* Update OptionsCreator.py

* Update OptionsCreator.py

* grammar
2025-11-30 01:23:13 +01:00
Doug Hoskisson
775065715d SNIClient: new SnesReader interface (#5155)
* SNIClient: new SnesReader interface

* fix Python 3.8 compatibility
`bisect_right`

* move to worlds
because we don't have good separation importable modules and entry points

* `read` gives object that contains data

* remove python 3.10 implementation and update typing

* remove obsolete comment

* freeze _MemRead and assert type of get parameter

* some optimization in `SnesData.get`

* pass context to `read` so that we can have a static instance of `SnesReader`

* add docstring to `SnesReader`

* remove unused import

* break big reads into chunks

* some minor improvements

- `dataclass` instead of `NamedTuple` for `Read`
- comprehension in `SnesData.__init__`
- `slots` for dataclasses

* update chunk size to 2048
2025-11-30 01:22:35 +01:00
Doug Hoskisson
4e608b13ae Docs: fix name of "Build APWorlds" component (#5703) 2025-11-30 01:18:11 +01:00
Colin
886cc68051 Timespinner: Exclude Removed Location from Web Tracker (#5701) 2025-11-29 19:13:43 +01:00
Ziktofel
146a314d22 SC2: Update Infested Banshee description to be more clear when the Burrow is unlocked #5685 2025-11-29 19:12:29 +01:00
Phaneros
18cf1bce36 sc2: Item group fixes and new item groups (#5679)
* sc2: Fixing missing buildings in Terran buildings group; adding sc1 and melee unit groups

* sc2: Removing out-of-place comment
2025-11-29 19:12:04 +01:00
wildham
f7e3f4e589 [FFMQ] Bugfix: Fix missing logic rule for Frozen Fields > Aquaria access 2025-11-29 19:11:07 +01:00
BlastSlimey
9f9765b78d shapez: Fix logic bug with vanilla shapes and floating layers #5623 2025-11-29 19:10:37 +01:00
Scipio Wright
8ae1a7da32 TUNIC: Fix fuse rule in lower zig #5621 2025-11-29 19:09:55 +01:00
Mysteryem
08ea3fe225 ALTTP: Fix setting Beat Agahnim 1 event twice (#5617)
alttp was setting the `Beat Agahnim 1` event onto the `Agahnim 1` location twice.

I was debugging a multiworld generation issue with various custom worlds, where, for debugging purposes, I changed `multiworld.push_item` to make it crash like `location.place_locked_item` when the location was already filled, which also identified this minor issue in alttp.
2025-11-29 19:09:30 +01:00
massimilianodelliubaldini
b81be6b4fc Jak and Daxter: Second attempt at fixing trade tests. #5599 2025-11-29 19:08:39 +01:00
LiquidCat64
f1aca0fc46 CVCotM: Add a client safeguard in case the player doesn't have Dash Boots #5500 2025-11-29 19:07:02 +01:00
Exempt-Medic
d88fe99780 DS3: Update/Fix Excluded Locations Logging (#5220)
* DS3: Fix Excluded Locations in Spoiler Log

* Update __init__.py

* update wording

* Comment out failing code
2025-11-29 19:04:07 +01:00
Carter Hesterman
360a1384f2 Civ6: Fix issue with names including civ-breaking characters (#5204) 2025-11-29 19:02:15 +01:00
Duck
d089b00ad5 Core: Add spaces in concatenated strings #5697 2025-11-29 18:52:08 +01:00
Duck
c05a2adc38 Wargroove: Add space in concatenated string #5696 2025-11-29 18:51:20 +01:00
Duck
7631242621 MLSS: Add space in concatenated string #5694 2025-11-29 18:50:34 +01:00
Duck
df48c3e718 KH1: Add space in concatenated string #5693 2025-11-29 18:48:46 +01:00
Duck
9a755e64b2 Jak and Daxter: Add space in concatenated string #5692 2025-11-29 18:48:23 +01:00
Duck
34d362a003 CV64/CVCotM: Add spaces in concatenated strings (#5691)
* Possible space removal

* Add spaces

* Missed one

* Revert removals, use newline
2025-11-29 18:47:54 +01:00
Duck
b75cce5d41 TLOZ: Add space in concatenated string #5690 2025-11-29 18:47:17 +01:00
threeandthreee
a07faca2d9 LADX: catch exception after closing magpie #5687 2025-11-29 18:46:22 +01:00
Phaneros
8a1a715dc4 SC2: logic fixes minor bugs (#5660)
* Pulsars no longer count as basic anti-air for protoss.
  * This is in response to player feedback that they were just too weak DPS-wise
* Haven's Fall (P) logic loosened slightly.
  * Void rays are now a one-unit solution to the rule
  * Scouts are now considered a one-unit solution to the rule
  * Two-unit solutions are now considered standard rather than advanced
  * Caladrius is now listed as an anti-muta unit for the two-unit solutions
  * This was discussed in the #SC2-dev channel.
    * Snarky did some testing and found that void rays were barely any worse than destroyers at handling mutas, and destroyers are already listed as a one-unit solution.
    * Snarky also found that scouts could mostly solo the mission at low skill level
    * Note that this rule only applies to the "beating the infestations" part of the mission; there are additional requirements for beating it, including a competent comp.
* The Host (T) now also can use SoA abilities if SoA presence is set to `any_race_lotv`, not just `everywhere`
2025-11-29 01:46:41 +01:00
Duck
60a192b1b6 ALttP/Factorio: Add spaces in concatenated strings (#5564)
* Add them

* Revert "Add them"

This reverts commit 82be86191f.

* Re-add ALttP/Factorio
2025-11-27 19:51:23 +01:00
NewSoupVi
3b721e0365 Tests: Move hosting test to APQuest #5671 2025-11-26 20:55:35 +01:00
Benny D
3e16c20fce PyCharm: fix the apworld builder run config (#5678)
* fix the apworld builder pycharm runner

* Update Build APWorld.run.xml

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-11-26 12:45:12 +01:00
Emerassi
ec2c39e82f Docs: Improve the documentation for priority locations to mention de-prioritized (#5631)
* Update the descriptions for priority and exclude locations to be more clear.

* Revision on priority

* Moved my change over to the documentation instead of the generated yaml comment.

* update per vi feedback

* Trying a 2 sentence approach

* more details!

* Update options api.md

* Update options api.md
2025-11-26 01:00:25 +01:00
NewSoupVi
23d319247f APQuest: Fix import of Protocol from bokeh instead of typing (#5674)
* APQuest: Fix import of Protocol from bokeh instead of typing

* bump world version
2025-11-25 23:45:55 +01:00
Fabian Dill
c2c488410f Core: Fix typo in docstring for hint_points in commonclient (#5673) 2025-11-25 22:40:57 +01:00
Fabian Dill
8ea49e76db Core: updates of requirements (#5672) 2025-11-25 22:40:32 +01:00
Phaneros
d834ecec6a SC2: Fix bugs and issues around excluded/unexcluded (#5644) 2025-11-25 20:44:07 +01:00
threeandthreee
f3000a89d4 LADX: Give better feedback during patching (#5401) 2025-11-25 20:42:55 +01:00
qwint
aa2774a5d5 Tests: Move world dependencies in tests to APQuest #5668 2025-11-25 19:26:37 +01:00
NewSoupVi
f9630fa13b Core: Add a bunch of validation to AutoPatchRegister (#5431)
* Add a bunch of validation to AutoPatchRegister

* slightly change it

* lmao
2025-11-25 00:38:42 +01:00
NewSoupVi
e0cbf77dae APQuest: Implement New Game (#5393)
* APQuest

* Add confetti cannon

* ID change on enemy drop

* nevermind

* Write the apworld

* Actually implement hard mode

* split everything into multiple files

* Push out webworld into a file

* Comment

* Enemy health graphics

* more ruff rules

* graphics :)

* heal player when receiving health upgrade

* the dumbest client of all time

* Fix typo

* You can kinda play it now! Now we just need to render the game... :)))

* fix kvui imports again

* It's playable. Kind of

* oops

* Sounds and stuff

* exceptions for audio

* player sprite stuff

* Not attack without sword

* Make sure it plays correctly

* Collect behavior

* ruff

* don't need to clear checked_locations, but do need to still clear finished_game

* Connect calls disconnect, so this is not necessary

* more seemless reconnection

* Ok now I think it's correct

* Bgm

* Bgm

* minor adjustment

* More refactoring of graphics and sound

* add graphics

* Item column

* Fix enemies not regaining their health

* oops

* oops

* oops

* 6 health final boss on hard mode

* boss_6.png

* Display APQuest items correctly

* auto switch tabs

* some mypy stuff

* Intro song

* Confetti Cannon

* a bit more confetti work

* launcher component

* Graphics change

* graphics and cleanup

* fix apworld

* comment out horse and cat for now

* add docs

* copypasta

* ruff made my comment look unhinged

* Move that comment

* Fix typing and don't import kvui in nogui

* lmao that already exists I don't need to do it myself

* Must've just copied this from somewhere

* order change

* Add unit tests

* Notes about the client

* oops

* another intro song case

* Write WebWorld and setup guides

* Yes description provided

* thing

* how to play

* Music and Volume

* Add cat and horse player sprites

* updates

* Add hammer and breakable wall

* TODO

* replace wav with ogg

* Codeowners and readme

* finish unit tests

* lint

* Todid

* Update worlds/apquest/client/ap_quest_client.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Update worlds/apquest/client/custom_views.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Filler pattern

* __future__ annotations

* twebhost

* Allow wasd and arrow keys

* correct wording

* oops

* just say the website

* append instead of +=

* qwint is onto my favoritism

* kitty alias

* Add a comment about preplaced items for assertAccessDependency

* Use classvar_matrix instead of MultiworldTestBase

* actually remove multiworld stuff from those tests

* missed one more

* Refactor a bit more

* Fix getting of the user path

* Actually explain components

* Meh

* Be a bit clearer about what's what

* oops

* More comments in the regions.py file

* Nevermind

* clarify regions further

* I use too many brackets

* Ok I'm done fr

* simplify wording

* missing .

* Add precollected example

* add note about precollected advancements

* missing s

* APQuest sound rework

* Volume slider

* I forgot I made this

* a

* fix volume of jingles

* Add math trap to game (only works in play_in_console mode so far)

* Math trap in apworld and client side

* Fix background during math trap

* fix leading 0

* Sound and further ui improvements for Math Trap

* fix music bug

* rename apquest subfolder to game

* Move comment to where it belongs

* Clear up language around components (hopefully)

* Clear up what CommonClient is

* Reword some more

* Mention Archipelago (the program) explicitly

* Update worlds/apquest/docs/en_APQuest.md

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

* Explain a bit more why you would use classvar matrix

* reword the assert raises stuff

* the volume slider thing is no longer true

* german game page

* Be more clear about why we're overriding Item and Location

* default item classification

* logically considered -> relevant to logic ()

* Update worlds/apquest/items.py

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

* a word on the ambiguity of the word 'filler'

* more rewording

* amount -> number

* stress the necessity of appending to the multiworld itempool

* Update worlds/apquest/locations.py

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

* get_location_names_with_ids

* slight rewording of the new helper method

* add some words about creating known location+item pairs

* Add some more words to worlds/apqeust/options.py

* more words in options.py

* 120 chars (thanks Ixrec >:((( LOL)

* Less confusing wording about rules, hopefully?

* victory -> completion

* remove the immediate creation of the hammer rule on the option region entrance

* access rule performance

* Make all imports module-level in world.py

* formatting

* get rid of noqa RUF012 (and also disable the rule in my local ruff.toml

* move comment for docstring closer to docstring in another place

* advancement????

* Missing function type annotations

* pass mypy again (I don't love this one but all the alternatives are equally bad)

* subclass instead of override

* I forgor to remove these

* Get rid of classvar_matrix and instead talk about some other stuff

* protect people a bit from the assertAccessDependency nonsense

* reword a bit more

* word

* More accessdependency text

* More accessdependency text

* More accessdependency text

* More accessdependency text

* oops

* this is supposed to be absolute

* Add some links to docs

* that's called game now

* Add an archipelago.json and explain what it means

* new line who dis

* reorganize a bit

* ignore instead of skip

* Update archipelago.json

* She new on my line till I

* Update archipelago.json

* add controls tab

* new ruff rule? idk

* WHOOPS

* Pack graphics into fewer files

* annoying ruff format thing

* Cleanup + mypy

* relative import

* Update worlds/apquest/client/custom_views.py

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

* Update generate_math_problem.py

* Update worlds/apquest/game/player.py

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

---------

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>
Co-authored-by: Ixrec <ericrhitchcock@gmail.com>
Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2025-11-25 00:38:06 +01:00
threeandthreee
447f8fba20 LADX: switch to asyncio.get_running_loop() (#5666) 2025-11-24 22:42:31 +01:00
Ziktofel
e60ea1765c SC2: Migrate external resources from user repos to sc2 organization (#5653) 2025-11-24 20:29:41 +01:00
Ziktofel
2d15c23681 SC2: Fix missing brackets in Zerg The Host logic (#5657)
* SC2: Fix missing brackets in Zerg The Host logic

* Allow usage of SoA any race LotV and add additional brackets
2025-11-23 19:37:50 +01:00
Jonathan Tan
c2f76d81ab TWW: Fix client sending duplicate magic meter (#5664) 2025-11-23 01:38:19 +01:00
Benjamin S Wolf
8b737cad21 Core: Better error message for invalid range values (#4038) 2025-11-22 02:55:04 +01:00
Spineraks
fd968d749e Yacht Dice: Add archipelago.json manifest #5658 2025-11-21 23:33:51 +01:00
Andres
32a021096b Factorio: Add connection change filtering functionality (#4997) 2025-11-21 02:30:11 +01:00
Silvris
3c819ec781 LttP: logic fixes and missing bombs (#5645)
3 logic issues:
* #3046 made it so that prizes were included in LttP's pre_fill items. It accounted for it in regular pre_fill, but missed stage_pre_fill.
* LttP defines a maximum number of heart pieces and heart containers logically within each difficulty. Item condensing did not account for this, and could reduce the number of heart pieces below the required amount logically. Notably, this makes some combination of settings much harder to generate, so another solution may end up ideal.
* Current logic rules do not properly account for the case of standard start and enemizer, requiring a large amount of items logically within a short number of locations. However, the behavior of Enemizer in this situation is well-defined, as the guards during the standard starting sequence are not changed. Thus the required items can be safely minimized.
2025-11-16 06:57:47 +01:00
Katelyn Gigante
01e64a2b69 Doc: Update Mac instructions to instruct the user to make a frozen bundle (#5614) 2025-11-16 02:04:23 +00:00
black-sliver
5e08c8bd98 Celeste (Open World): fix tutorial link on game page (#5627) 2025-11-15 16:57:50 +00:00
josephwhite
24aa4af7c2 WebHost: Validation for webworld themes (#5083) 2025-11-15 16:55:13 +01:00
NewSoupVi
b3c323ede3 The Witness: Fix CreateHints spoiling vague hints (#5359)
* Encode non-local vague hints as negative player number

* comments

* also bump req client version
2025-11-15 16:22:56 +01:00
NewSoupVi
3ec1e9184b Core: Only error in playthrough generation if game is not beatable (#5430)
* Core: Only error in playthrough generation if game is not beatable

The current flow of accessibility works like this:

```
if fulfills_accessibility fails:
    if multiworld can be beaten:
        log a warning
    else:
        raise Exception

if playthrough is enabled:
    if any progression items are not reachable:
        raise Exception
```

This means that if you do a generation where the game is beatable but some full players' items are not reachable, it doesn't crash on accessibility check, but then crashes on playthrough. This means that **whether it crashes depends on whether you have playthrough enabled or not**.

Imo, erroring on something accessibility-related is outside of the scope of create_playthrough. Create_playthrough only needs to care about whether it can fulfill its own goal - Building a minimal playthrough to everyone's victory.
The actual accessibility check should take care of the accessibility.

* Reword

* Simplify sentence
2025-11-15 03:38:33 +01:00
NewSoupVi
5055f87034 The Witness: Add archipelago.json (#5481)
* Add archipelago.json to witness

* Update archipelago.json
2025-11-15 03:36:53 +01:00
Dinopony
3bb43b266f Landstalker: Add manifest file (#5629) 2025-11-15 03:27:41 +01:00
Justus Lind
c2094a9fc4 Muse Dash: Update Song list to Medium5 Echoes (#5597) 2025-11-15 03:26:20 +01:00
Silvris
b82878130c Core: add random range and additional random descriptions to template yaml (#5586) 2025-11-15 03:10:23 +01:00
Silvris
8fbd3569ce Core: add a local yaml creator GUI (#4900)
Adds a GUI for the creation of simple yamls (no weighting) locally.
2025-11-15 02:49:59 +01:00
Katelyn Gigante
494381b272 Factorio: Add no-enemies mode to worldgen schema (#5542) 2025-11-15 02:46:35 +01:00
Ziktofel
7422b10a3d SC2: Fix the goal mission tooltip depending on goal missions' status (#5577) 2025-11-15 02:44:27 +01:00
threeandthreee
e4b5591582 CV64: Fix not having Clocktower Key3 when placed in a start_inventory (#5592) 2025-11-15 02:20:53 +01:00
Ziktofel
557a284afd SC2: Fix custom mission order if used in weights.yaml (#5604) 2025-11-15 02:18:58 +01:00
LiquidCat64
75eb2660ce CV64: Fix not having Clocktower Key3 when placed in a start_inventory (#5596) 2025-11-15 02:18:18 +01:00
Phaneros
34e13c5e5a SC2: Adjusting and slightly simplifying mission difficulty pool adjustment configuration (#5587) 2025-11-15 02:17:35 +01:00
Fly Hyping
d098372913 Wargroove 1: added archipelago.json (#5591) 2025-11-15 02:16:31 +01:00
Snowflav_
7e8746c01b Pokémon R/B: Specify encounter types for Dexsanity hint data (#5574) 2025-11-15 02:13:34 +01:00
Phaneros
93d3d8b084 SC2: Fixing a gap in the ascendant upgrades in the tracker (#5570) 2025-11-15 02:12:51 +01:00
Snarky
98273ddad9 SC2: Add Manifest (#5559) 2025-11-15 02:12:15 +01:00
threeandthreee
c408c53598 LADX: create manifest (#5563) 2025-11-15 02:11:31 +01:00
Salzkorn
cde73c5a2b SC2: Move race_swap pick_one functionality to mission picking (#5538) 2025-11-15 02:10:35 +01:00
Phaneros
d7eb95a2ee SC2: Allowing unexcluded_items to affect items excluded by vanilla_items_only (#5520) 2025-11-15 02:09:57 +01:00
Mysteryem
a2f8877810 Core: Fix #5605 - Trigger values being shared by weights.yaml slots (#5636)
The "+" and "-" trigger operations modify sets/lists in-place, but
triggers could set a value to the same set/list for multiple slots using
weights.yaml.

This fix deep-copies all values set from new (trigger) weights to ensure
that the values do not get shared across multiple slots.
2025-11-14 21:58:44 +01:00
NewSoupVi
5779dda937 Core: Deprecate Utils.get_options by July 31st, 2025 (#4811)
* 0.4.4 lol

* Pycharm pls

* Violet pls

* Remove OptionsType

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-11-14 15:58:06 +01:00
Omnises Nihilis
d597bc40a2 Docs: Add troubleshooting section to kh1_en.md, typo fix in kh1/Options.py (#5615)
* kh1 docs update

* small grammar

* suggested fix

client is die (sadge)

* h2/h3 -> ##/###

* oops that's my bad
2025-11-14 08:28:55 +00:00
black-sliver
4a41550cad CI: update pytest to 9.0.1 (#5637) 2025-11-14 08:26:34 +00:00
Doug Hoskisson
e4fd06482e Core: don't use union type just to reuse a name (#5246)
This is the "followup PR" to address these comments:
https://github.com/ArchipelagoMW/Archipelago/pull/5071#discussion_r2117417408

It's better to have a different name for different representations of the data, so that someone reading the code doesn't need to wonder whether it has gone through the transformation or not.
2025-11-12 12:35:19 +01:00
NewSoupVi
dba03e3a76 Choo Choo Charles: Raise InvalidItemError instead of bare Exception (#5429) 2025-11-12 12:33:26 +01:00
black-sliver
4b2298e168 SC2: make worlds._sc2common.bot.proto a regular package (#5626)
This is currently required for import reasons
and has a test that fails without it.
2025-11-11 23:19:20 +01:00
black-sliver
283badfc7e SoE: add apworld manifest (#5557)
* SoE: add APWorld manifest

* SoE: small typing fixes
2025-11-11 18:16:38 +00:00
GreenestBeen
088f2cc269 SC2: Remove dependency on s2clientprotocol and update protobuf version (#5474) 2025-11-11 18:58:20 +01:00
massimilianodelliubaldini
ea40156194 Jak 1: Remove PAL-only instructions, no longer needed. (#5598) 2025-11-11 16:05:43 +00:00
Adrian Priestley
0bf48d7a1b fix(workflows): Update branch filter in Docker workflow (#5616)
* fix(workflows): Update branch filter in Docker workflow
- Change branch filter from wildcard to 'main'
- Ensures that the workflow only triggers on the main branch
2025-11-10 00:41:16 +01:00
Gurglemurgle
14f261b1dd Launcher: add skip_open_folder arg to Generate Template Options (#5302) 2025-11-10 00:31:43 +01:00
Ziktofel
bec625621a SC2 Tracker: Fix bundled Protoss W/A upgrade display (#5612) 2025-11-09 22:45:55 +01:00
Duck
19db58907a Game Docs: Fix main setup guide links (#5603) 2025-11-09 19:55:37 +00:00
Fabian Dill
77808d3ae9 Core: Bump version from 0.6.4 to 0.6.5 (#5607) 2025-11-09 03:07:47 +01:00
Fabian Dill
b2b0d15add Core: add export_datapackage tool (#5609) 2025-11-09 03:07:23 +01:00
Vertraic
ecadb301c0 Core: Allows Meta.yaml to add triggers to individual yaml's categories. (#3556)
* Initial commit

* Shifted added code to the appropriate indentation.
Re-wrote for statement in proper python style.

* Update Generate.py

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

* change to an elif to avoid unnecessary nesting

---------

Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: Benny D <78334662+benny-dreamly@users.noreply.github.com>
2025-11-08 23:45:26 +00:00
black-sliver
360ad7197b CI: downgrade pytest to 8.4.2 (#5613)
Also move ci requirements to separate file for easier handling.
2025-11-09 00:05:36 +01:00
Yaranorgoth
96ae2235d1 CCCharles: Fix editorial issues in documentations (#5611)
* Fix editorial issues from Setup Guides

* Fix editorial issues in documentations

* Fix extra typos in documentations
2025-11-08 23:10:36 +01:00
Jacob Lewis
37b87e3fde [Docs] Update docs/network protocol.md/NetworkVersion to include class field (#5377)
* update docs NetworkVersion

* added in non-common-client version clarification

* Update docs/network protocol.md

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

---------

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>
2025-11-08 22:15:29 +01:00
Adrian Priestley
5b6714d2c0 chore(documentation): Update deployment example config (#5476)
- Include flag and notice regarding asset rights in example config
2025-11-08 17:21:27 +01:00
LiquidCat64
97c07e91d1 CVCotM: Fix determinism with Halve DSS Cards Placed (#5601) 2025-11-03 19:31:36 +01:00
black-sliver
7cd7111241 CI: use rehosted appimage runtime and appimagetool (#5595)
This fixes the problem of CI randomly breaking when upstream pushes
updates and allows better reproducibility of builds.
2025-10-31 08:34:31 +01:00
NewSoupVi
4b0306102d WebHost: Pin Flask-Compress to 1.18 for all versions of Python (#5590)
* WebHost: Pin Flask-Compress to 1.18 for all versions of Python

* oop
2025-10-26 11:40:21 +01:00
LiquidCat64
3f139f2efb CV64: Fix Explosive DeathLink not working with Increase Shimmy Speed on #5523 2025-10-26 11:39:14 +01:00
Subsourian
41a62a1a9e SC2: added MindHawk to credits (#5549) 2025-10-26 08:54:17 +01:00
black-sliver
8837e617e4 WebHost, Multiple Worlds: fix images not showing in guides (#5576)
* Multiple: resize FR RA network commands screenshot

This is now more in line with the text (and the english version).

* Multiple: optimize EN RA network commands screenshot

The URL has changed, so it's a good time to optimize.

* WebHost, Worlds: fix retroarch images not showing

Implements a src/url replacement for relative paths.
Moves the RA screenshots to worlds/generic since they are shared.
Also now uses the FR version in ffmq.
Also fixes the formatting that resultet in the list breaking.
Also moves imports in render_markdown.

Guides now also properly render on Github.

* Factorio: optimize screenshots

The URL has changed, so it's a good time to optimize.

* Factorio: change guide screenshots to use relative URL

* Test: markdown: fix tests on Windows

We also can't use delete=True, delete_on_close=False
because that's not supported in Py3.11.

* Test: markdown: fix typo

I hope that's it now. *sigh*

* Landstalker: fix doc images not showing

Change to relative img urls.

* Landstalker: optimize doc PNGs

The URL has changed, so it's a good time to optimize.
2025-10-25 22:19:38 +02:00
black-sliver
2bf410f285 CI: update appimagetool to 2025-10-19 (#5578)
Beware: this has a bug, but it does not impact our CI.
2025-10-25 16:49:05 +00:00
NewSoupVi
04fe43d53a kvui: Fix audio being completely non-functional on Linux (#5588)
* kvui: Fix audio on Linux

* Update kvui.py
2025-10-25 15:34:59 +02:00
NewSoupVi
643f61e7f4 Core: Add a ruff.toml to the root directory (#5259)
* Add a ruff.toml to the root directory

* spell out C901

* Add target version

* Add some more of the suggested rules

* ignore PLC0415

* TC is bad

* ignore B0011

* ignore N818

* Ignore some more rules

* Add PLC1802 to ignore list

* Update ruff.toml

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

* oops

* R to RET and RSC

* oops

* Py311

* Update ruff.toml

---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2025-10-25 00:19:42 +02:00
black-sliver
6b91ffecf1 WebHost: add missing docutils requirement ... (#5583)
... and update it to latest.
This is being used in WebHostLib.options directly.
A recent change bumped our required version, so this is actually a fix.
2025-10-24 00:55:10 +02:00
black-sliver
4f7f092b9b setup: check if the sign host is on a local network (#5501)
Could have a really bad timeout if it goes through default route and packet is dropped.
2025-10-24 00:54:27 +02:00
gaithern
df3c6b7980 KH1: Add specified encoding to file output from Client to avoid crashes with non ASCII characters (#5584)
* Fix Slot 2 Level Checks description

* Fix encoding issue
2025-10-23 23:01:02 +02:00
threeandthreee
19839399e5 LADX: stealing logic option (#3965)
* implement StealingInLogic option

* fix ladxr setting

* adjust docs

* option to disable stealing

* indicate disabled stealing with shopkeeper dialog

* merge upstream/main

* Revert "merge upstream/main"

This reverts commit c91d2d6b29.

* fix

* stealing in patch

* logic reorder and fix

sword to front for readability, but also can_farm condition was missing
2025-10-23 22:11:41 +02:00
CookieCat
4847be98d2 AHIT: Fix death link timestamps being incorrect (#5404) 2025-10-23 05:30:46 +02:00
black-sliver
3105320038 Test: check fields in world source manifest (#5558)
* Test: check game in world manifest

* Update test/general/test_world_manifest.py

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

* Test: rework finding expected manifest location

* Test: fix doc comment

* Test: fix wrong custom_worlds path in test_world_manifest

Also simplifies the way we find ./worlds/.

* Test: make test_world_manifest easier to extend

* Test: check world_version in world manifest

according to docs/apworld specification.md

* Test: check no container version in source world manifest

according what was added to docs/apworld specification.md in PR 5509

* Test: better assertion messages in test_world_manifest.py

* Test: fix wording in world source manifest

---------

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>
2025-10-22 01:52:44 +02:00
Silvris
e8c8b0dbc5 MM2: fix Proteus reading #5575 2025-10-21 19:10:39 +02:00
Duck
c199775c48 Pokemon RB: Fix likely unintended concatenation #5566 2025-10-20 21:48:17 +02:00
Duck
d2bf7fdaf7 AHiT: Fix likely unintended concatenation #5565 2025-10-20 21:47:49 +02:00
Duck
621ec274c3 Yugioh: Fix likely unintended concatenations (#5567)
* Fix likely unintended concatenations

* Yeah that makes sense why I thought there were more here
2025-10-20 21:47:16 +02:00
NewSoupVi
7cd73e2710 WebHost: Fix generate argparse with --config-override + add autogen unit tests so we can test that (#5541)
* Fix webhost argparse with extra args

* accidentally added line

* WebHost: fix some typing

B64 url conversion is used in test/hosting,
so it felt appropriate to include this here.

* Test: Hosting: also test autogen

* Test: Hosting: simplify stop_* and leave a note about Windows compat

* Test: Hosting: fix formatting error

* Test: Hosting: add limitted Windows support

There are actually some differences with MP on Windows
that make it impossible to run this in CI.

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-10-20 17:40:32 +02:00
NewSoupVi
708df4d1e2 WebHost: Fix flask-compress to 1.18 for Python 3.11 (to get CI to pass again) (#5573)
From Discord:

Well, flask-compress updated and now our 3.11 CI is failing

Why? They switched to a lib called backports.zstd
And 3.11 pkg_resources can't handle that.

pip finds it. But in our ModuleUpdate.py, we first pkg_resources.require packages, and this fails. I can't reproduce this locally yet, but in CI, it seems like even though backports.zstd is installed, it still fails on it and prompts installing it over and over in every unit test
Now what do we do :KEKW:
Black Sliver suggested pinning flask-compress for 3.11
But I would just like to point out that this means we can't unpin it until we drop 3.11
the real thing is we probably need to move away from pkg_resources? lol 
since it's been deprecated literally since the oldest version we support
2025-10-20 17:06:07 +02:00
black-sliver
914a534a3b WebHost: fix gen timeout/exception resource handling (#5540)
* WebHost: reset Generator proc title on error

* WebHost: fix shutting down autogen

This is still not perfect but solves some of the issues.

* WebHost: properly propagate JOB_TIME

* WebHost: handle autogen shutdown
2025-10-20 09:16:29 +02:00
NewSoupVi
11d18db452 Docs: APWorld documentation, make a distinction between APWorld and .apworld (#5509)
* APWorld docs: Make a distinction between APWorld and .apworld

* Update apworld specification.md

* Update apworld specification.md

* Be more anal about the launcher component

* Update apworld specification.md

* Update apworld specification.md
2025-10-19 09:05:34 +02:00
Nicholas Saylor
00acfe63d4 WebHost: Update publish_parts parameters (#5544)
old name is deprecated and new name allows both writer instance or alias/name.
2025-10-19 03:40:25 +02:00
Fafale
2ac9ab5337 Docs: add warning about BepInEx to HK translated setup guides (#5554)
* Update HK pt-br setup to add warning about BepInEx

* Update HK spanish setup guide to add warning about BepInEx
2025-10-19 03:36:35 +02:00
Benny D
2569c9e531 DLC Quest: Enable multi-classification items (#5552)
* implement prog trap item (thanks stardew)

* oops that's wrong

* okay this is right
2025-10-19 03:30:24 +02:00
Rosalie
946f227226 [FF1] Added Deep Dungeon locations to locations.json so they exist in the datapackage (#5392)
* Added DD locations to locations.json so they exist in the datapackage.

* Update worlds/ff1/data/locations.json

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

* Update worlds/ff1/data/locations.json

Forgot trailing commas aren't allowed in JSON.

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

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: qwint <qwint.42@gmail.com>
2025-10-17 16:44:11 +02:00
Carter Hesterman
7ead8fdf49 Civ 6: Add era requirements for boosts and update boost prereqs (#5296)
* Resolve #5136

* Resolves #5210
2025-10-17 16:35:44 +02:00
Rosalie
f5f554cb3d [FF1] Client fix and improvement (#5390)
* FF1 Client fixes.

* Strip leading/trailing spaces from rom-stored player name.

* FF1R encodes the name as utf-8, as it happens.

* UTF-8 is four bytes per character, so we need 64 bytes for the name, not 16.
2025-10-17 16:34:10 +02:00
Alchav
3f2942c599 Super Mario Land 2: Logic fixes #5258
Co-authored-by: alchav <alchav@jalchavware.com>
2025-10-17 16:32:58 +02:00
Snarky
da519e7f73 SC2: fix incorrect preset option (#5551)
* SC2: fix incorrect preset option

* SC2: fix incorrect evil logic preset option

---------

Co-authored-by: Snarky <sparkykueken@gmail.com>
2025-10-17 16:30:05 +02:00
Duck
0718ada682 Core: Allow PlandoItems to be pickled (#5335)
* Add Options.PlandoItem

* Remove worlds.generic.PlandoItem handling

* Add plando pickling test

* Revert old PlandoItem cleanup

* Deprecate old PlandoItem

* Change to warning message

* Use deprecated decorator
2025-10-17 03:20:34 +02:00
Duck
f756919dd9 CI: Add worlds manifests to build action trigger (#5555)
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-10-16 23:58:12 +02:00
Jérémie Bolduc
406b905dc8 Stardew Valley: Add archipelago.json (#5535)
* add apworld manifest

* add world version
2025-10-16 22:23:23 +02:00
JaredWeakStrike
91439e0fb0 KH2: Manifest eletric boogaloo (#5556)
* manifest file

* x y z for world version

* Update archipelago.json
2025-10-16 20:25:11 +02:00
RoobyRoo
03bd59bff6 Ocarina of Time: Create manifest (#5536)
* Create archipelago.json

* Sure, let's call it 7.0.0

* Update archipelago.json

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-10-16 11:48:04 +02:00
BlastSlimey
cf02e1a1aa shapez: Fix floating layers logic error #5263 2025-10-15 23:41:15 +02:00
JaredWeakStrike
f6d696ea62 KH2: Manifest File (#5553)
* manifest file

* x y z for world version
2025-10-15 23:40:21 +02:00
BadMagic100
123acdef23 Docs: warn HK users not to use BepInEx #5550 2025-10-15 13:35:00 +02:00
Nicholas Saylor
28c7a214dc Core: Use Better Practices Accessing Manifests (#5543)
* Close manifest files

* Name explicit encoding
2025-10-15 01:09:05 +02:00
NewSoupVi
bdae7cd42c MultiServer: Fix hinting multi-copy items bleeding found status (#5547)
* fix hinting multi-copy items bleeding found status

* reword
2025-10-14 20:44:01 +02:00
Silvris
fc404d0cf7 MM2: fix Heat Man always being invulnerable to Atomic Fire #5546 2025-10-14 09:27:41 +02:00
threeandthreee
5ce71db048 LADX: use start_inventory_from_pool (#4641) 2025-10-13 19:32:49 +02:00
NewSoupVi
aff98a5b78 CommonClient: Fix manually connecting to a url when the username or password has a space in it (#5528)
* CommonClient: Fix manually connecting to a url when the username or password has a space in it

* Update CommonClient.py

* Update CommonClient.py
2025-10-13 18:55:44 +02:00
Exempt-Medic
30cedb13f3 Core: Limit ItemLink Name to 16 Characters (#4318) 2025-10-13 18:32:53 +02:00
Seldom
0c1ecf7297 Terraria: Remove /apstart from docs (#5537) 2025-10-13 18:06:25 +02:00
black-sliver
5390561b58 MultiServer: Fix breaking weakrefs for SetNotify (#5539) 2025-10-12 21:46:16 +02:00
threeandthreee
bb457b0f73 SNI Client: fix that it isnt using host.yaml settings (#5533) 2025-10-11 11:16:47 +02:00
threeandthreee
6276ccf415 LADX: move client out of root (#4226)
* init

* Revert "init"

This reverts commit bba6b7a306.

* put it back but clean

* pass args

* windows stuff

* delete old exe

this seems like it?

* use marin icon in launcher

* use LauncherComponents.launch
2025-10-10 17:56:15 +02:00
Mysteryem
d3588a057c Tests: gc.freeze() by default in the test\benchmark\locations.py (#5055)
Without `gc.freeze()` and `gc.unfreeze()` afterward, the `gc.collect()`
call within each benchmark often takes much longer than all 100_000
iterations of the location access rule, making it difficult to benchmark
all but the slowest of access rules.

This change enables using `gc.freeze()` by default.
2025-10-10 17:19:52 +02:00
Katelyn Gigante
30ce74d6d5 core: Add host.yaml setting to make !countdown configurable (#5465)
* core:  Add host.yaml setting to make !countdown configurable

* Store /option changes to countdown_mode in save file

* Wording changes in host.yaml

* Use .get

* Fix validation for /option command
2025-10-10 15:02:56 +02:00
NewSoupVi
ff59b86335 Docs: More apworld manifest documentation (#5477)
* Expand apworld specification manifest part

* clarity

* expand example

* clarify

* correct

* Correct

* elaborate on what version is

* Add where the apworlds are output

* authors & update versions

* Update apworld specification.md

* Update apworld specification.md

* Update apworld specification.md

* Update apworld specification.md
2025-10-09 20:23:21 +02:00
NewSoupVi
e355d20063 WebHost: Don't show e.__cause__ on the generation error page #5521 2025-10-08 07:22:14 +02:00
Fabian Dill
28ea2444a4 kvui: re-enable settings menu (#4823) 2025-10-08 06:34:00 +02:00
black-sliver
e907980ff0 MultiServer: slight optimizations (#5527)
* Core: optimize MultiServer.Client

* Core: optimize websocket compression settings
2025-10-08 02:22:34 +02:00
Snarky
5a933a160a SC2: Add option presets (#5436)
* SC2: Add option presets

* SC2: Address reviews

* SC2: Fix import

* SC2: Update key mode

* SC2: Update renamed option

* sc2: PR comment; switching from __dataclass_fields__ to dataclasses.fields()

* sc2: Changing quote style to match AP standard

* sc2: PR comments; Switching to Starcraft2.type_hints

---------

Co-authored-by: Snarky <sparkykueken@gmail.com>
Co-authored-by: MatthewMarinets <matthew.marinets@gmail.com>
2025-10-07 17:25:08 +02:00
Duck
c7978bcc12 Docs: Add info about custom worlds (#5510)
* Cleaning up (#4)

Cleanup

* Added new paragraph for new games

* Update worlds/generic/docs/setup_en.md

Proofier-comitting

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

* Added a mention in the header of the games page to refer to this guide if needed.

* Small tweaks

* Added mention regarding alternate version of worlds

* Update WebHostLib/templates/supportedGames.html

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

* Update worlds/generic/docs/setup_en.md

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

* Edits for comments

* Slight alternate versions rewording

* Edit subheadings

* Adjust link text

* Replace alternate versions section and reword first

---------

Co-authored-by: Danaël V <104455676+ReverM@users.noreply.github.com>
Co-authored-by: Rever <danael.villeneuve@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-10-06 04:48:42 +02:00
Duck
5c7a84748b WebHost: Handle blank values for OptionCounters #5517 2025-10-06 04:38:38 +02:00
Duck
8dc9719b99 Core: Cleanup unneeded use of Version/tuplize_version (#5519)
* Remove weird version uses

* Restore version var

* Unrestore version var
2025-10-06 01:56:09 +02:00
black-sliver
60617c682e WebHost: fix log fetching extra characters when there is non-ascii (#5515) 2025-10-05 21:05:52 +02:00
massimilianodelliubaldini
fd879408f3 WebHost: Improve user friendliness of generation failure webpage (#4964)
* Improve user friendliness of generation failure webpage.

* Add details to other render for seedError.html.

* Refactor css to avoid !important tags.

* Update WebHostLib/static/styles/themes/ocean-island.css

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

* Update WebHostLib/generate.py

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

* use f words

* small refactor

* Update WebHostLib/generate.py

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

* Fix whitespace.

* Update one new use of seedError template for pickling errors.

---------

Co-authored-by: qwint <qwint.42@gmail.com>
2025-10-05 15:38:57 +02:00
Mysteryem
8decde0370 Core: Don't waste swaps by swapping two copies of the same item (#5516)
There is a limit to the number of times an item can be swapped to
prevent swapping going on potentially forever. Swapping an item with a
copy of itself is assumed to be a pointless swap, and was wasting
possible swaps in cases where there were multiple copies of an item
being placed.

This swapping behaviour was noticed from debugging solo LADX generations
that was wasting swaps by swapping copies of the same item.

This patch adds a check that if the placed_item and item_to_place are
equal, then the location is skipped and no attempt to swap is made.

If worlds do intend to have seemingly equal items to actually have
different logical behaviour, those worlds should override __eq__ on
their Item subclasses so that the item instances are not considered
equal.

Generally, fill_restrictive should only be used with progression items,
so it is assumed that swapping won't have to deal with multiple copies
of an item where some copies are progression and some are not. This is
relevant because Item.__eq__ only compares .name and .player.
2025-10-05 15:07:12 +02:00
PoryGone
adb5a7d632 SA2B, DKC3, SMW, Celeste 64, Celeste (Open World): Manifest manifests 2025-10-05 06:47:01 +02:00
Jérémie Bolduc
f07fea2771 CommonClient: Move command marker to last_autofillable_command (#4907)
* handle autocomplete command when press question

* fix test

* add docstring to get_input_text_from_response

* fix line lenght
2025-10-05 05:39:30 +02:00
James White
a2460b7fe7 Pokemon RB: Add client tracking for tracker relevant events (#5495)
* Pokemon RB: Add client tracking for tracker relevant events

* Pokemon RB: Use list for tracker events

* Pokemon RB: Use correct bill event

* Pokemon RB: Add champion event tracking
2025-10-05 05:33:52 +02:00
Katelyn Gigante
f8f30f41b7 Launcher: Newly installed custom worlds are not relative #4989
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-10-05 05:30:52 +02:00
Benny D
60070c2f1e PyCharm: add a run config for the new apworld builder workflow (#5489)
* add Build APWorld PyCharm run config

* change casing of the argument

* Update Build APWorld.run.xml

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-10-05 05:13:04 +02:00
Louis M
3eb25a59dc Aquaria: Updating documentation to add latest clients informations (#5438)
* Updating Aquaria documentation to add latest clients informations

* Typo in the permission explanation
2025-10-05 05:08:34 +02:00
Branden Wood
1cbc5d6649 Short Hike: improve setup guide docs #5470 2025-10-05 05:08:15 +02:00
DJ-lennart
bdef410eb2 Civilization VI: Update for the setup instructions #5286 2025-10-05 05:07:11 +02:00
Duck
ec9145e61d Region: Use Mapping type for adding locations/exits #5354 2025-10-05 05:04:02 +02:00
Duck
a547c8dd7d Core: Add location count field for world to spoiler log (#5440)
* Add location count

* Only count non-events

* Add total count
2025-10-05 05:02:26 +02:00
PinkSwitch
7996fd8d19 Core: Update start inventory description to mention item quantities (#5460)
* SNIClient: new SnesReader interface

* fix Python 3.8 compatibility
`bisect_right`

* move to worlds
because we don't have good separation importable modules and entry points

* `read` gives object that contains data

* remove python 3.10 implementation and update typing

* remove obsolete comment

* freeze _MemRead and assert type of get parameter

* some optimization in `SnesData.get`

* pass context to `read` so that we can have a static instance of `SnesReader`

* add docstring to `SnesReader`

* remove unused import

* break big reads into chunks

* some minor improvements

- `dataclass` instead of `NamedTuple` for `Read`
- comprehension in `SnesData.__init__`
- `slots` for dataclasses

* Change descriptions

* Fix sni client?

---------

Co-authored-by: beauxq <beauxq@yahoo.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2025-10-05 05:01:56 +02:00
Scipio Wright
7a652518a3 [Website docs] Update wording of "adding a game to archipelago" section 2025-10-05 04:59:52 +02:00
Duck
ae4426af08 Core: Pad version string in world printout #5511 2025-10-05 04:46:26 +02:00
black-sliver
91e97b68d4 Webhost: eagerly free resources in customserver (#5512)
* Unref some locals that would live long for no reason.
* Limit scope of db_session in init_save.
2025-10-05 03:49:56 +02:00
NewSoupVi
6a08064a52 Core: Assert that if an apworld manifest file exists, it has a game field (#5478)
* Assert that if an apworld manifest file exists, it has a game field

* god damnit

* Update worlds/LauncherComponents.py

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

* Update setup.py

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

---------

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2025-10-04 03:04:23 +02:00
Kaito Sinclaire
83cfb803a7 SMZ3: Fix forced fill behaviors (GT junk fill, initial Super/PB front fill) (#5361)
* SMZ3: Make GT fill behave like upstream SMZ3 multiworld GT fill

This means: All items local, 50% guaranteed filler, followed by possible
useful items, never progression.

* Fix item links

* SMZ3: Ensure in all cases, we remove the right item from the pool

Previously front fill would cause erratic errors on frozen, with the
cause immediately revealed by, on source, tripping the assert that was
added in #5109

* SMZ3: Truly, *properly* fix GT junk fill

After hours of diving deep into the upstream SMZ3 randomizer, it finally
behaves identically to how it does there
2025-10-03 02:05:29 +02:00
qwint
6d7abb3780 Webhost: Ignore Invalid Worlds in Webhost (#5433)
* filter world types at top of webhost so worlds that aren't loadable in webhost are "uninstalled"

* mark invalid worlds, show error if any, then filter to exclude them
2025-10-03 01:56:11 +02:00
Silvris
50f6cf04f6 Core: "Build APWorlds" cleanup (#5507)
* allow filtered build, subprocess

* component description

* correct name

* move back to running directly
2025-10-02 09:36:33 +02:00
qwint
b162095f89 Launcher: Rework apworld install popup #5508 2025-10-01 21:54:41 +02:00
Silvris
33b485c0c3 Core: expose world version to world classes and yaml (#5484)
* support version on new manifest

* apply world version from manifest

* Update Generate.py

* docs

* reduce mm2 version again

* wrong version

* validate game in world_types

* Update Generate.py

* let unknown game fall through to later exception

* hide real world version behind property

* named tuple is immutable

* write minimum world version to template yaml, fix gen edge cases

* punctuation

* check for world version in autoworldregister

* missed one

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-10-01 02:47:08 +02:00
Ziktofel
4893ac3e51 SC2: Fix Terran global upgrades present even if no Terran build missions are rolled (#5452)
* Fix Terran global upgrades present even if no Terran build missions are rolled

* Code cleanup
2025-10-01 02:40:30 +02:00
Phaneros
76b0197462 SC2: any_unit and item parent bugfixes (#5480)
* sc2: Fixing a Reaver item being classified as a scout item

* sc2: any_units now requires any AA in the first 5 units
* Fixing Shoot the Messenger not requiring AA in a hard rule
* Fixing any_unit zerg still allowing unupgraded mercs

* sc2: Fixed an issue where terran was requiring zerg anti-air in any_units
2025-09-30 22:18:42 +02:00
Scipio Wright
6a63de2f0f TUNIC: Fuse and Bell Shuffle (#5420)
* Making the fix better (thanks medic)

* Make it actually return false if it gets to the backup lists and fails them

* Fix stuff after merge

* Add outlet regions, create new regions as needed for them

* Put together part of decoupled and direction pairs

* make direction pairs work

* Make decoupled work

* Make fixed shop work again

* Fix a few minor bugs

* Fix a few minor bugs

* Fix plando

* god i love programming

* Reorder portal list

* Update portal sorter for variable shops

* Add missing parameter

* Some cleanup of prints and functions

* Fix typo

* it's aliiiiiive

* Make seed groups not sync decoupled

* Add test with full-shop plando

* Fix bug with vanilla portals

* Handle plando connections and direction pair errors

* Update plando checking for decoupled

* Fix typo

* Fix exception text to be shorter

* Add some more comments

* Add todo note

* Remove unused safety thing

* Remove extra plando connections definition in options

* Make seed groups in decoupled with overlapping but not fully overlapped plando connections interact nicely without messing with what the entrances look like in the spoiler log

* Fix weird edge case that is technically user error

* Add note to fixed shop

* Fix parsing shop names in UT

* Remove debug print

* Actually make UT work

* multiworld. to world.

* Fix typo from merge

* Make it so the shops show up in the entrance hints

* Fix bug in ladder storage rules

* Remove blank line

* # Conflicts:
#	worlds/tunic/__init__.py
#	worlds/tunic/er_data.py
#	worlds/tunic/er_rules.py
#	worlds/tunic/er_scripts.py
#	worlds/tunic/rules.py
#	worlds/tunic/test/test_access.py

* Fix issues after merge

* Update plando connections stuff in docs

* Make early bushes only contain grass

* Fix library mistake

* 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>

* has_stick -> has_melee

* has_stick -> has_melee

* Add a failsafe for direction pairing

* Fix playthrough crash bug

* Remove init from logicmixin

* Updates per code review (thanks hesto)

* has_stick to has_melee in newer update

* has_stick to has_melee in newer update

* 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>

* Starting out

* Rules for breakable regions

* # Conflicts:
#	worlds/tunic/__init__.py
#	worlds/tunic/combat_logic.py
#	worlds/tunic/er_data.py
#	worlds/tunic/er_rules.py
#	worlds/tunic/er_scripts.py

* Cleanup more stuff after merge

* Revert "Cleanup more stuff after merge"

This reverts commit a6ee9a93da.

* Revert "# Conflicts:"

This reverts commit c74ccd74a4.

* Cleanup more stuff after merge

* 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

* make the rest of it work, it's pr ready, boom

* Make it work in not pot shuffle

* Merge grass rando

* multiworld -> world get_location, use has_any

* Swap out region for West Garden Before Terry grass

* Adjust west garden rules to add west combat region

* Adjust grass regions for south checkpoint grass

* Adjust grass regions for after terry grass

* Adjust grass regions for west combat grass

* Adjust grass regions for dagger house grass

* Adjust grass regions for south checkpoint grass, adjust regions and rules for some related locations

* Finish the remainder of the west garden grass, reformat ruined atoll a little

* More hex quest updates

- Implement page ability shuffle for hex quest
- Fix keys behind bosses if hex goal is less than 3
- Added check to fix conflicting hex quest options
- Add option to slot data

* Change option comparison

* Change option checking and fix some stuff

- also keep prayer first on low hex counts

* Update option defaulting

* Update option checking

* Fix option assignment again

* Merge in hex hunt

* Merge in changes

* Clean up imports

* Add ability type to UT stuff

* merge it all

* Make local fill work across pot and grass (to be adjusted later)

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

* Fix id overlap

* Update option description

* Fix default

* Reorder localfill option desc

* Load the purgatory ones in

* Adjustments after merge

* Fully remove logicrules

* Fix UT support with fixed shop option

* Add breakable shuffle to the ut stuff

* Make it load in a specific number of locations

* Add Silent's spoiler log ability thing

* Fix for groups

* Fix for groups

* Fix typo

* Fix hex quest UT support

* Use .get

* UT fixes, classification fixes

* Rename some locations

* Adjust guard house names

* Adjust guard house names

* Rework create_item

* Fix for plando connections

* Rename, add new breakables

* Rename more stuff

* Time to rename them again

* Fix issue with fixed shop + decoupled

* Put in an exception to catch that error in the future

* Update create_item to match main

* Update spoiler log lines for hex abilities

* Burn the signs down

* Bring over the combat logic fix

* Merge in combat logic fix

* Silly static method thing

* Move a few areas to before well instead of east forest

* Add an all_random hidden option for dev stuff

* Port over changes from main

* Fix west courtyard pot regions

* Remove debug prints

* Fix fortress courtyard and beneath the fortress loc groups again

* Add exception handling to deal with duplicate apworlds

* Fix typo

* More missing loc group conversions

* Initial fuse shuffle stuff

* Fix gun missing from combat_items, add new for combat logic cache, very slight refactor of check_combat_reqs to let it do the changeover in a less complicated fashion, fix area being a boss area rather than non-boss area for a check

* Add fuse shuffle logic

* reorder atoll statue rule

* Update traversal reqs

* Remove fuse shuffle from temple door

* Combine rules and option checking

* Add bell shuffle; fix fuse location groups

* Fix portal rules not requiring prayer

* Merge the grass laurels exit grass PR

* Merge in fortress bridge PR

* Do a little clean up

* Fix a regression

* Update after merge

* Some more stuff

* More Silent changes

* Update more info section in game info page

* Fix rules for atoll and swamp fuses

* Precollect cathedral fuse in ER

* actually just make the fuse useful instead of progression

* Add it to the swamp and cath rules too

* Fix cath fuse name

* Minor fixes and edits

* Some UT stuff

* Fix a couple more groups

* Move a bunch of UT stuff to its own file

* Fix up a couple UT things

* Couple minor ER fixes

* Formatting change

* UT poptracker stuff enabled since it's optional in one of the releases

* Add author string to world class

* Adjust local fill option name

* Update ut_stuff to match the PR

* Add exception handling for UT with old apworld

* Fix missing tracker_world

* Remove extra entrance from cath main -> elevator

Entry <-> Elev exists,
Entry <-> Main exists
So no connection is needed between Main and Elev

* Fix so that decoupled doesn't incorrectly use get_portal_info and get_paired_portal

* Fix so that decoupled doesn't incorrectly use get_portal_info and get_paired_portal

* Update for breakables poptracker

* Backup and warnings instead

* Update typing

* Delete old regions and rules, move stuff to logic_helpers and constants

* Delete now much less useful tests

* Fix breakables map tracking

* Add more comments to init

* Add todo to grass.py

* Fix up tests

* Fully remove fixed_shop

* Finish hard deprecating FixedShop

* Fix zig skip showing up in decoupled fixed shop

* Make local_fill show up on the website

* Merge with main

* Fixes after merge

* More fixes after merge

* oh right that's why it was there, circular imports

* Swap {} to ()

* Add fuse and bell shuffle to seed groups since they're logically significant for entrance pairing

---------

Co-authored-by: silent-destroyer <osilentdestroyer@gmail.com>
Co-authored-by: Silent <110704408+silent-destroyer@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-09-30 21:39:41 +02:00
NewSoupVi
e6fb7d9c6a Core: Add an "options" arg to setup_multiworld so that non-default options can be set in it #5414 2025-09-30 20:23:33 +02:00
Fabian Dill
0882c0fa97 Core: only store persistent changes if there are changes (#5311) 2025-09-30 19:27:43 +02:00
threeandthreee
f26fcc0eda LADX: use generic slot name for slots 101+ (#5208)
* init

* we already had the generic name, just use it

* cap hints at 101

* nevermind, the name is just baked in here
2025-09-30 18:47:17 +02:00
Goblin God
50c9d056c9 KH1: Fix a small error in option descriptions #5445 2025-09-30 18:40:20 +02:00
threeandthreee
5cec3f45f5 LADX: reorganize options page (#4851)
* init

* merge upstream/main

* improve option tooltips, clean up file a bit

* ladx feels like more of an ocean game

* one more

* more cleanup

* some reorg

* Apply suggestions from code review

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

* clean up accidental newlines

* rewording

* dont do the ohko alias

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-09-30 18:39:53 +02:00
Katelyn Gigante
448f214cdb core: Option to skip "unused" item links (#4608)
* core:  Option to skip "unused" item links

* Update worlds/generic/docs/advanced_settings_en.md

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

* Update BaseClasses.py

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>
2025-09-30 18:39:04 +02:00
Phaneros
49f2d30587 Sc2: [performance] change default options (#5424)
* sc2: Changing default campaign options to something more performative and desirable for new players

* sc2: Fixing broken test that was missed in roundup

* SC2: Update tests for new defaults

* SC2: Fix incomplete test

* sc2: Updating description for enabled campaigns to mention which are free to play

* sc2: PR comments; Updating additional unit tests that were affected by a default change

* sc2: Adding a comment to the Enabled Campaigns option to list all the valid campaign names

* sc2: Adding quotes wrapping sample values in enabled_campaigns comment to aid copy-pasting

---------

Co-authored-by: Salzkorn <salzkitty@gmail.com>
2025-09-30 18:36:41 +02:00
Ziktofel
897d5ab089 SC2: Fix Conviction logic for Grant Story Tech (#5419)
* Fix Conviction logic for Grant Story Tech

- Kinetic Blast and Crushing Grip is available for the mission if story tech is granted

* Review updates
2025-09-30 18:35:26 +02:00
Phaneros
92ff0ddba8 SC2: Launcher bugfixes after content merge (#5409)
* sc2: Fixing Launcher.py launch not properly handling command-line arguments

* sc2: Fixing some old option names in webhost

* sc2: Switching to common client url parameter handling
2025-09-30 18:34:26 +02:00
Duck
1d2ad1f9c9 Docs: More type annotation changes (#5301)
* Update docs annotations

* Update settings recommendation

* Remove Dict in comment
2025-09-30 18:32:50 +02:00
threeandthreee
516ebc53ce LADX: fix local lvl 2 sword on the beach turning into a lvl 0 shield #5334
e3e49b16d6
2025-09-30 18:31:49 +02:00
Silvris
a30b43821f KDL3, MM2: set goal condition before generate basic (#5382)
* move goal kdl3

* mm2

* missed the singular important line
2025-09-30 18:30:26 +02:00
gaithern
d9955d624b KH1: Fix Slot 2 Level Checks description #5451 2025-09-30 05:10:29 +02:00
NewSoupVi
5345937966 The Witness: Remove two things from slot_data that nothing uses anymore #5502 2025-09-30 04:45:59 +02:00
massimilianodelliubaldini
580370c3a0 Jak and Daxter: close Power Cell loophole in trades test #5493 2025-09-30 04:43:59 +02:00
Scipio Wright
c30a5b206e Noita: Add archipelago.json (#5483)
* Add archipelago.json

* Add authors

* make it a list
2025-09-30 04:12:19 +02:00
Bryce Wilson
053f876e84 Pokemon Emerald: Add manifest (#5487) 2025-09-30 04:10:45 +02:00
massimilianodelliubaldini
ab2097960d Jak and Daxter: Add manifest #5492 2025-09-30 03:54:32 +02:00
Justus Lind
2f23dc72f9 Muse Dash: Update song list to Legendary Voyage, Mystic Treasure. Add manifest. (#5498)
* Legendary Voyage, Mystic Treasure Update

* Add manifest

* Correct Manifest version.

* Fix file encoding
2025-09-30 03:54:14 +02:00
Felix R
f9083d9307 bumpstik: Create manifest (#5496) 2025-09-30 03:53:47 +02:00
Felix R
25baa57850 meritous: Create manifest (#5497) 2025-09-30 03:53:31 +02:00
Scipio Wright
47b2242c3c TUNIC: Add archipelago.json (#5482)
* add archipelago.json

* newline

* Add authors

* Make it a list
2025-09-30 03:53:10 +02:00
Fabian Dill
6099869c59 Core: new cx_freeze (#5316) 2025-09-30 01:52:12 +02:00
palex00
1d861d1d06 Pokémon RB: Update Slot Data (#5494) 2025-09-28 23:18:06 +02:00
Bryce Wilson
d1624679ee Pokemon Emerald: Set all abilities to Cacophony if all are blacklisted (#5488) 2025-09-28 21:39:18 +02:00
Bryce Wilson
12998bf6f4 Pokemon Emerald: Fix missing fanfare address (#5490) 2025-09-27 16:54:03 +02:00
NewSoupVi
24394561bd Core: Bump Container Version to 7, and make APWorldContainer use 7 as the compatible_version #5479 2025-09-25 05:10:23 +02:00
Fabian Dill
4ae87edf37 Core: apworld manifest launcher component (#5340)
adds a launcher component that builds all apworlds on top of #4516
---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-09-24 23:25:46 +02:00
Etsuna
4525bae879 Webhost: add total player location counts to tracker API (#5441) 2025-09-24 20:08:14 +02:00
Fabian Dill
dc270303a9 Core: improve formatting on /help command (#5381) 2025-09-24 17:33:44 +02:00
Fabian Dill
a99da85a22 Core: APWorld manifest (#4516)
Adds support for a manifest file (archipelago.json) inside an .apworld file. It tells AP the game, minimum core version (optional field), maximum core version (optional field), its own version (used to determine which file to prefer to load only currently)
The file itself is marked as required starting with core 0.7.0, prior, just a warning is printed, with error trace.

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-09-24 02:39:19 +02:00
CaitSith2
e256abfdfb Factorio: Allow to reconnect a timed out RCON client connection. (#5421) 2025-09-22 03:07:33 +02:00
Fabian Dill
fb9011da63 WebHost: revamp /api/*tracker/ (#5388) 2025-09-22 00:25:12 +02:00
Fabian Dill
68187ba25f WebHost: remove team argument from tracker arguments where it's irrelevant (#5272) 2025-09-22 00:17:10 +02:00
Fabian Dill
6c45c8d606 Core: make countdown a "admin" only command (#5463) 2025-09-21 19:23:29 +02:00
threeandthreee
9e96cece56 LADX: Fix quickswap #5399 2025-09-21 18:59:40 +02:00
agilbert1412
1bd44e1e35 Stardew Valley: Fixed Traveling merchant flaky test (#5434)
* - Made the traveling cart test not be flaky due to worlds caching

# Conflicts:
#	worlds/stardew_valley/rules.py

* - Made the traveling merchant test less flaky

# Conflicts:
#	worlds/stardew_valley/test/rules/TestTravelingMerchant.py
2025-09-21 18:58:15 +02:00
Phaneros
7badc3e745 SC2: Logic bugfixes (#5461)
* sc2: Fixing always-true rules in locations.py; fixed two over-constrained rules that put vanilla out-of-logic

* sc2: Minor min2() optimization in rules.py

* sc2: Fixing a Shatter the Sky logic bug where w/a upgrades were checked too many times and for the wrong units
2025-09-21 18:54:22 +02:00
Scipio Wright
3af1e92813 TUNIC: Update name of a chest in the UT poptracker map integration #5462 2025-09-21 18:47:11 +02:00
Fabian Dill
73718bbd61 Core: make APContainer seek archipelago.json (#5261) 2025-09-19 03:52:31 +02:00
Sunny Bat
8f2b4a961f Raft: Add Zipline Tool requirement to Engine controls blueprint #5455 2025-09-16 19:26:06 +02:00
JaredWeakStrike
9fdeecd996 KH2: Remove top level client script (#5446)
* initial commit

* remove kh2client.exe from setup
2025-09-15 02:08:57 +02:00
Adrian Priestley
174d89c81f feat(workflow): Implement new Github workflow for building and pushing container images (#5242)
* fix(workflows): Update Docker workflow tag pattern
- Change tag pattern from "v*" to "*.*.*" for better version matching
- Add new semver pattern type for major version

* squash! fix(workflows): Update Docker workflow tag pattern - Change tag pattern from "v*" to "*.*.*" for better version matching - Add new semver pattern type for major version

* Update docker.yml

* Update docker.yml

* Update docker.yml

* fix(docker): Correct copy command to use recursive flag for EnemizerCLI
- Changed 'cp' to 'cp -r' to properly copy EnemizerCLI directory

* fixup! Update docker.yml

* fix(docker): Correct copy command to use recursive flag for EnemizerCLI
- Changed 'cp' to 'cp -r' to properly copy EnemizerCLI directory

* chore(workflow): Update Docker workflow to support multiple platforms
- Removed matrix strategy for platform selection
- Set platforms directly in the Docker Buildx step

* docs(deployment): Update container deployment documentation
- Specify minimum versions for Docker and Podman
- Add requirement for Docker Buildx plugin

* fix(workflows): Exclude specific paths from Docker build triggers
- Prevent unnecessary builds for documentation and deployment files

* feat(ci): Update Docker workflow for multi-architecture builds
- Added new build job for ARM64 architecture support
- Created a multi-arch manifest to manage image variants
- Improved Docker Buildx setup and push steps for both architectures

* fixup! feat(ci): Update Docker workflow for multi-architecture builds - Added new build job for ARM64 architecture support - Created a multi-arch manifest to manage image variants - Improved Docker Buildx setup and push steps for both architectures

* fixup! feat(ci): Update Docker workflow for multi-architecture builds - Added new build job for ARM64 architecture support - Created a multi-arch manifest to manage image variants - Improved Docker Buildx setup and push steps for both architectures

* fixup! feat(ci): Update Docker workflow for multi-architecture builds - Added new build job for ARM64 architecture support - Created a multi-arch manifest to manage image variants - Improved Docker Buildx setup and push steps for both architectures

* fix(workflow): Cleanup temporary image tags

* fixup! fix(workflow): Cleanup temporary image tags

* fixup! fix(workflow): Cleanup temporary image tags

* fixup! fix(workflow): Cleanup temporary image tags

* fix(workflow): Apply scoped build cache to eliminate race condition
between jobs.

* fixup! fix(workflow): Apply scoped build cache to eliminate race condition between jobs.

* Remove branch wildcard

* Test comment

* Revert wildcard removal

* Remove `pr` event

* Revert `pr` event removal

* fixup! Revert `pr` event removal

* Update docker.yml

* Update docker.yml

* Update docker.yml

* feat(workflows): Add docker workflow to compute final tags
- Introduce a step to compute final tags based on GitHub ref type
- Ensure 'latest' tag is set for version tags

* chore(workflow): Enable manual dispatch for Docker workflow
- Add workflow_dispatch event trigger to allow manual runs

* fix(workflows): Update Docker workflow to handle tag outputs correctly
- Use readarray to handle tags as an array
- Prevent duplicate latest tags in the tags list
- Set multiline output for tags in GitHub Actions

* Update docker.yml

Use new `is_not_default_branch` condition

* Update docker.yml

Allow "v" prefix for semver git tags qualifying for `latest` image tag

* Update docker.yml

Tighten up `tags` push pattern mirroring that of `release` workflow.

* Merge branch 'ArchipelagoMW:main' into main

* Update docker.yml

* Merge branch 'ArchipelagoMW:main' into docker_wf

* Update docker.yml

Use new `is_not_default_branch` condition

* Update docker.yml

Allow "v" prefix for semver git tags qualifying for `latest` image tag

* Update docker.yml

Tighten up `tags` push pattern mirroring that of `release` workflow.

* ci(docker): refactor multi-arch build to use matrix strategy
- Consolidate separate amd64 and arm64 jobs into a single build job
- Introduce matrix for platform, runner, suffix, and cache-scope
- Generalize tag computation and build steps with matrix variables

* fixup! ci(docker): refactor multi-arch build to use matrix strategy - Consolidate separate amd64 and arm64 jobs into a single build job - Introduce matrix for platform, runner, suffix, and cache-scope - Generalize tag computation and build steps with matrix variables
2025-09-14 14:24:53 +02:00
Duck
71de33d7dd CI: Fix peer review tag on undrafting a PR (#5282)
* Move ready for review condition out of non-draft check

* Remove condition on labeler

* Revert condition
2025-09-14 00:02:03 +00:00
Fabian Dill
9c00eb91d6 WebHost: fix Internal Server Error if parallel access to /room/* happens (#5444) 2025-09-14 02:01:41 +02:00
NewSoupVi
597583577a KH1: Remove top level script & remove script_name from its component (#5443) 2025-09-13 16:07:13 +02:00
Salzkorn
4e085894d2 SC2: Region access rule speedups (#5426) 2025-09-12 23:48:29 +02:00
Yaranorgoth
76a8b0d582 CCCharles: Bug fix for cyclic connections of Entrances with the ignored rules by the logic (#5442)
* Add cccharles world to AP

> The logic has been tested, the game can be completed
> The logic is simple and it does not take into account options
! The documentations are a work in progress

* Update documentations

> Redacted French and English Setup Guides
> Redacted French and English Game Pages

* Handling PR#5287 remarks

> Revert unexpected changes on .run\Archipelago Unittests.run.xml (base Archipelago file)
> Fixed typo "querty" -> "qwerty" in fr and eng Game Pages
> Adding "Game page in other languages" section to eng Game Page documentation
> Improved Steam path in fr and eng Setup Guides

* Handled PR remarks + fixes

> Added get_filler_item_name() to remove warnings
> Fixed irrelevant links for documentations
> Used the Player Options page instead of the default YAML on GitHub
> Reworded all locations to make them simple and clear
> Split some locations that can be linked with an entrance rule
> Reworked all options
> Updated regions according to locations
> Replaced unnecessary rules by rules on entrances

* Empty Options.py

Only the base options are handled yet, "work in progress" features removed.

* Handled PR remark

> Fixed specific UT name

* Handled PR remarks

> UT updated by replacing depreciated features

* Add start_inventory_from_pool as option

This start_inventory_from_pool option is like regular start inventory but it takes items from the pool and replaces them with fillers

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

* Handled PR remarks

> Mainly fixed editorial and minor issues without impact on UT results (still passed)

* Update the guides according to releases

> Updated the depreciated guides because the may to release the Mod has been changed
> Removed the fixed issues from 'Known Issues'
> Add the "Mod Download" section to simplify the others sections.

* Handled PR remark

> base_id reduced to ensure it fits to signed int (32 bits) in case of future AP improvements

* Handled PR remarks

> Set topology_present to False because unnecessary
> Added an exception in case of unknown item instead of using filler classification
> Fixed an issue that caused the "Bug Spray" to be considered as filler
> Reworked the test_claire_breakers() test to ensure the lighthouse mission can only be finished if at least 4 breakers are collected

* Added Choo-Choo Charles to README.md

* CCCharles: Added rules to win

> The victory could be accessed from sphere 1, this is now fixed by adding the following items as requirements:
- Temple Key
- Green Egg
- Blue Egg
- Red Egg

* CCCharles: Fixed cyclic Entrances connections

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-09-12 23:32:42 +02:00
NewSoupVi
27e50aa81a MultiServer: Make it so hint_location doesn't set an automatic priority #4713 2025-09-11 00:42:52 +02:00
Ben Dixon
aaaceebd91 Timespinner: Add Boss Rando Type Options (#4466)
* adding in boss rando type options for Timespinner

* removing new options from the backwards compatible section

* adding in boss rando type options for Timespinner

* removing new options from the backwards compatible section

* re-adding accidentally deleted line

* better documenting the different boss rando types

* adding missing options to the interpret_slot_data function

* making boss override schema more strict and allow for weights

* now actually rolling using the weights for boss rando overrides

* adding boss rando overrides to the spoiler header

* simplifying the schema for the manual boss mappings
2025-09-10 23:56:04 +02:00
gaithern
1322ce866e Kingdom Hearts: Adding a bunch of new features (#5078)
* Change vanilla_emblem_pieces to randomize_emblem_pieces

* Add jungle slider and starting tools options

* Update option name and add preset

* GICU changes

* unnecessary

* Update Options.py

* Fix has_all

* Update Options.py

* Update Options.py

* Some potenitial logic changes

* Oops

* Oops 2

* Cups choice options

* typos

* Logic tweaks

* Ice Titan and Superboss changes

* Suggested change and one more

* Updating some other option descriptions for clarity/typos

* Update Locations.py

* commit

* SYNTHESIS

* commit

* commit

* commit

* Add command to change communication path

I'm not a python programmer, so do excuse the code etiquette. This aims to allow Linux users to communicate to their proton directory.

* commit

* commit

* commit

* commit

* commit

* commit

* commit

* commit

* Update Client.py

* Update Locations.py

* Update Regions.py

* commit

* commit

* commit

* Update Rules.py

* commit

* commit

* commit

* commit logic changes and linux fix from other branch

* commit

* commit

* Update __init__.py

* Update Rules.py

* commit

* commit

* commit

* commit

* add starting accessory setting

* fix starting accessories bug

* Update Locations.py

* commit

* add ap cost rando

* fix some problem locations

* add raft materials

* Update Client.py

* OK WORK THIS TIME PLEASE

* Corrected typos

* setting up for logic difficulty

* commit 1

* commit 2

* commit 3

* minor error fix

* some logic changes and fixed some typos

* tweaks

* commit

* SYNTHESIS

* commit

* commit

* commit

* commit

* commit

* commit

* commit

* commit

* commit

* commit

* commit

* Update Client.py

* Update Locations.py

* Update Regions.py

* commit

* commit

* commit

* Update Rules.py

* commit

* commit

* commit

* commit logic changes and linux fix from other branch

* commit

* commit

* Update __init__.py

* Update Rules.py

* commit

* commit

* commit

* commit

* add starting accessory setting

* fix starting accessories bug

* Update Locations.py

* commit

* add ap cost rando

* fix some problem locations

* add raft materials

* Update Client.py

* cleanup

* commit 4

* tweaks 2

* tweaks 3

* Reset

* Update __init__.py

* Change vanilla_emblem_pieces to randomize_emblem_pieces

* Add jungle slider and starting tools options

* unnecessary

* Vanilla Puppies Part 1

The easy part

* Update __init__.py

I'm not certain this is the exact right chest for Tea Party Garden, Waterfall Cavern, HT Cemetery, or Neverland Hold but logically it's the same. 
Will do a test run later and fix if need be

* Vanilla Puppies Part 3

Wrong toggle cause I just copied over Emblem Pieces oops

* Vanilla Puppies Part 4

Forgor commented out code

* Vanilla Puppies Part 5

I now realize how this works and that what I had before was redundant

* Update __init__.py

Learning much about strings

* cleanup

* Update __init__.py

Only missed one!

* Update option name and add preset

* GICU changes

* Update Options.py

* Fix has_all

* Update Options.py

* Update Options.py

* Cups choice options

* typos

* Ice Titan and Superboss changes

* Some potenitial logic changes

* Oops

* Oops 2

* Logic tweaks

* Suggested change and one more

* Updating some other option descriptions for clarity/typos

* Update Locations.py

* Add command to change communication path

I'm not a python programmer, so do excuse the code etiquette. This aims to allow Linux users to communicate to their proton directory.

* Moving over changes from REVAMP

* whoops

* Fix patch files on the website

* Update test_goal.py

* commit

* Update worlds/kh1/__init__.py

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

* change some default options

* Missed a condition

* let's try that

* Update Options.py

* unnecessary sub check

* Some more cleanup

* tuples

* add icon

* merge cleanup

* merge cleanup 2

* merge clean up 3

* Update Data.py

* Fix cups option

* commit

* Update Rules.py

* Update Rules.py

* phantom tweak

* review commit

* minor fixes

* review 2

* minor typo fix

* minor logic tweak

* Update Client.py

* Update __init__.py

* Update Rules.py

* Olympus Cup fixes

* Update Options.py

* even MORE tweaks

* commit

* Update Options.py

* Update has_x_worlds

* Update Rules.py

* commit

* Update Options.py

* Update Options.py

* Update Options.py

* tweak 5

* Add Stacking Key Items and Halloween Town Key Item Bundle

* Update worlds/kh1/Rules.py

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

* Update Rules.py

* commit

* Update worlds/kh1/__init__.py

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

* Update __init__.py

* Update __init__.py

* whoops

* Update Rules.py

* Update Rules.py

* Fix documentation styling

* Clean up option help text

* Reordering options so they're consistent and fixing a logic bug when EOTW Unlock is item but door is emblems

* Make have x world logic consider if the player has HAW on or not

* Fix Atlantica beginner logic things, vanilla keyblade stats being broken, and some behind boss locations

* Fix vanilla puppy option

* hotfix for crabclaw logic

* Fix defaults and some boss locations

* Fix server spam

* Remove 3 High Jump Item Workshop Logic, small client changes

* Updates for PR

---------

Co-authored-by: esutley <ecsutley@gmail.com>
Co-authored-by: Goblin God <37878138+esutley@users.noreply.github.com>
Co-authored-by: River Buizel <4911928+rocket0634@users.noreply.github.com>
Co-authored-by: omnises <OmnisGamers@gmail.com>
Co-authored-by: Omnises Nihilis <38057571+Omnises@users.noreply.github.com>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-09-10 23:49:32 +02:00
Colin
78b529fc23 Timespinner: Adds Lantern Check flags, Missing Traps (#5188)
* Timespinner: Add Torch Flags

* Add comment of all torch locations

* Add gyre and dark forest lanterns

* Add Ancient Pyramid

* Don't make cube default progression

* Add Emperors Tower

* Add lake desolation, forest

* Add lab

* Add library, varndagroth

* Add hangar

* Add ramparts

* Add Xarion

* Add castle keep

* Add royal towers

* Add lake serene

* Add remaining checks

* Add missing region

* Fix region names

* Fix location id

* Add traps to settings

* Add restriction to elevator keycard torch

* Set new traps to have quantity 0 by default

* Scythe is now useful due to torch shredding

* Add additional lantern

* Un-disable missing lantern

* Include location ids in tracker

* Remove additional space

* Fix paren

* Add missing lantern

* Remove tablet requirement for torches

* Update filler V card

* Fix brackets

* Address feedback
2025-09-10 16:27:13 +02:00
Rosalie
9aa0bf7245 FF1: New Maintainership (#5027)
* Submitting myself for FF1 maintainership

* Uncommented an important line.
2025-09-10 00:42:32 +02:00
Fabian Dill
287bb638a0 Docs: Kivy Style (#5425)
Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-09-09 19:33:31 +02:00
PoryGone
18ac9210cb SA2B: Logic Fixes and Black Market Trap Name Improvements (#5427)
* Logic fixes and more Chao and Fake Item names

* Fix typo

* Overhaul Shop Trap Item names
2025-09-09 03:29:31 +02:00
qwint
17dad8313e Test: Remove most dependencies on lttp (#5338)
* removes the last dependencies on lttp in tests

* removing test.bases.TestBase from docs as well

* rename bases

* move imports to bases
2025-09-08 21:36:26 +02:00
qwint
63f3512829 Core: adds a custom KeyError for invalid item names (#4223)
* adds a custom KeyError for raising on world.create_item() if the passed in name is invalid

* Update __init__.py

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-09-08 11:11:46 +02:00
lgbarrere
1b200fb20b Choo-Choo Charles: implement new game and documentations (#5287)
* Add cccharles world to AP

> The logic has been tested, the game can be completed
> The logic is simple and it does not take into account options
! The documentations are a work in progress

* Update documentations

> Redacted French and English Setup Guides
> Redacted French and English Game Pages

* Handling PR#5287 remarks

> Revert unexpected changes on .run\Archipelago Unittests.run.xml (base Archipelago file)
> Fixed typo "querty" -> "qwerty" in fr and eng Game Pages
> Adding "Game page in other languages" section to eng Game Page documentation
> Improved Steam path in fr and eng Setup Guides

* Handled PR remarks + fixes

> Added get_filler_item_name() to remove warnings
> Fixed irrelevant links for documentations
> Used the Player Options page instead of the default YAML on GitHub
> Reworded all locations to make them simple and clear
> Split some locations that can be linked with an entrance rule
> Reworked all options
> Updated regions according to locations
> Replaced unnecessary rules by rules on entrances

* Empty Options.py

Only the base options are handled yet, "work in progress" features removed.

* Handled PR remark

> Fixed specific UT name

* Handled PR remarks

> UT updated by replacing depreciated features

* Add start_inventory_from_pool as option

This start_inventory_from_pool option is like regular start inventory but it takes items from the pool and replaces them with fillers

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

* Handled PR remarks

> Mainly fixed editorial and minor issues without impact on UT results (still passed)

* Update the guides according to releases

> Updated the depreciated guides because the may to release the Mod has been changed
> Removed the fixed issues from 'Known Issues'
> Add the "Mod Download" section to simplify the others sections.

* Handled PR remark

> base_id reduced to ensure it fits to signed int (32 bits) in case of future AP improvements

* Handled PR remarks

> Set topology_present to False because unnecessary
> Added an exception in case of unknown item instead of using filler classification
> Fixed an issue that caused the "Bug Spray" to be considered as filler
> Reworked the test_claire_breakers() test to ensure the lighthouse mission can only be finished if at least 4 breakers are collected

* Added Choo-Choo Charles to README.md

* CCCharles: Added rules to win

> The victory could be accessed from sphere 1, this is now fixed by adding the following items as requirements:
- Temple Key
- Green Egg
- Blue Egg
- Red Egg

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-09-08 10:37:51 +02:00
Duck
8a091c9e02 Kivy: Fix MessageBox popups (#5193) 2025-09-06 19:21:36 +02:00
black-sliver
c3c517a200 DS3: use yaml.safe_load (#5360) 2025-09-06 19:09:41 +02:00
black-sliver
c5b404baa8 CI: only trigger release action for bare semver (#5065) 2025-09-05 23:33:13 +02:00
NewSoupVi
77cab13827 ArchipIDLE: Remove game #5422 2025-09-05 23:20:37 +02:00
Scipio Wright
31b2eed1f9 TUNIC: Make the local_fill option show up on the website #5348 2025-09-05 17:09:33 +02:00
Fabian Dill
e23720a977 LttP: shuffle around gitignore (#5307) 2025-09-05 16:48:39 +02:00
Fabian Dill
90058ee175 CommonClient: fix /items, /locations and /missing not working if the datapackage is local (#5350) 2025-09-05 16:48:15 +02:00
Ziktofel
5c6dbdd98f SC2: Update docs for Linux launch script to follow the core client migration (#5407) 2025-09-05 16:44:28 +02:00
Ziktofel
8c2d246a53 SC2: Restrict allow Orphan to missions that already require that (#5405)
* Restrict Allow Orphan for items to missions that already require that

* Add test for build mission orphan behavior

* Update item lists for Allow Orphan flag

* Update the unit test to clear that BotB is not in the mission list

* Update unit test name
2025-09-05 16:44:01 +02:00
qwint
0d26b6426f Core: Remove lttp module requirement from generation #5384 2025-09-05 16:42:12 +02:00
Alchav
b9fb5c8b44 Super Mario Land 2: Remove erroneous Coinsanity checks #5364
Co-authored-by: alchav <alchav@jalchavware.com>
2025-09-05 16:37:31 +02:00
Scipio Wright
e518e41f67 Hollow Knight: Make the connecting header separate from the yaml one (#5353)
* Update setup_en.md

* Update setup_pt_br.md
2025-09-05 16:34:57 +02:00
qwint
7a38e44e64 Test: Deprecate TestBase (#5339)
* deprecate TestBase and fix the last use of it in main

* actually delete it because test discovery also imports it lmao
2025-09-05 16:24:20 +02:00
Jérémie Bolduc
64d3c55d62 Stardew Valley: Add money logic to traveling merchant (#5327)
* add rule to traveling merchant region

* add a test so kaito is happy
2025-09-05 16:23:25 +02:00
Kaito Sinclaire
89be26a33a Heretic: Update Steam URL (#5304) 2025-09-05 16:22:11 +02:00
Kaito Sinclaire
5b5e2c3567 SMZ3: Fix distribution of SM prizes (#5303) 2025-09-05 16:21:08 +02:00
Exempt-Medic
ef59a5ee11 TUNIC: Change non_local_items Earlier (#5249) 2025-09-04 19:04:21 -04:00
Scipio Wright
b0b3e3668f TUNIC: The Big Refactor (#5195)
* Make it actually return false if it gets to the backup lists and fails them

* Fix stuff after merge

* Add outlet regions, create new regions as needed for them

* Put together part of decoupled and direction pairs

* make direction pairs work

* Make decoupled work

* Make fixed shop work again

* Fix a few minor bugs

* Fix a few minor bugs

* Fix plando

* god i love programming

* Reorder portal list

* Update portal sorter for variable shops

* Add missing parameter

* Some cleanup of prints and functions

* Fix typo

* it's aliiiiiive

* Make seed groups not sync decoupled

* Add test with full-shop plando

* Fix bug with vanilla portals

* Handle plando connections and direction pair errors

* Update plando checking for decoupled

* Fix typo

* Fix exception text to be shorter

* Add some more comments

* Add todo note

* Remove unused safety thing

* Remove extra plando connections definition in options

* Make seed groups in decoupled with overlapping but not fully overlapped plando connections interact nicely without messing with what the entrances look like in the spoiler log

* Fix weird edge case that is technically user error

* Add note to fixed shop

* Fix parsing shop names in UT

* Remove debug print

* Actually make UT work

* multiworld. to world.

* Fix typo from merge

* Make it so the shops show up in the entrance hints

* Fix bug in ladder storage rules

* Remove blank line

* # Conflicts:
#	worlds/tunic/__init__.py
#	worlds/tunic/er_data.py
#	worlds/tunic/er_rules.py
#	worlds/tunic/er_scripts.py
#	worlds/tunic/rules.py
#	worlds/tunic/test/test_access.py

* Fix issues after merge

* Update plando connections stuff in docs

* Make early bushes only contain grass

* Fix library mistake

* 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>

* has_stick -> has_melee

* has_stick -> has_melee

* Add a failsafe for direction pairing

* Fix playthrough crash bug

* Remove init from logicmixin

* Updates per code review (thanks hesto)

* has_stick to has_melee in newer update

* has_stick to has_melee in newer update

* 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>

* Starting out

* Rules for breakable regions

* # Conflicts:
#	worlds/tunic/__init__.py
#	worlds/tunic/combat_logic.py
#	worlds/tunic/er_data.py
#	worlds/tunic/er_rules.py
#	worlds/tunic/er_scripts.py

* Cleanup more stuff after merge

* Revert "Cleanup more stuff after merge"

This reverts commit a6ee9a93da.

* Revert "# Conflicts:"

This reverts commit c74ccd74a4.

* Cleanup more stuff after merge

* 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

* make the rest of it work, it's pr ready, boom

* Make it work in not pot shuffle

* Merge grass rando

* multiworld -> world get_location, use has_any

* Swap out region for West Garden Before Terry grass

* Adjust west garden rules to add west combat region

* Adjust grass regions for south checkpoint grass

* Adjust grass regions for after terry grass

* Adjust grass regions for west combat grass

* Adjust grass regions for dagger house grass

* Adjust grass regions for south checkpoint grass, adjust regions and rules for some related locations

* Finish the remainder of the west garden grass, reformat ruined atoll a little

* More hex quest updates

- Implement page ability shuffle for hex quest
- Fix keys behind bosses if hex goal is less than 3
- Added check to fix conflicting hex quest options
- Add option to slot data

* Change option comparison

* Change option checking and fix some stuff

- also keep prayer first on low hex counts

* Update option defaulting

* Update option checking

* Fix option assignment again

* Merge in hex hunt

* Merge in changes

* Clean up imports

* Add ability type to UT stuff

* merge it all

* Make local fill work across pot and grass (to be adjusted later)

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

* Fix id overlap

* Update option description

* Fix default

* Reorder localfill option desc

* Load the purgatory ones in

* Adjustments after merge

* Fully remove logicrules

* Fix UT support with fixed shop option

* Add breakable shuffle to the ut stuff

* Make it load in a specific number of locations

* Add Silent's spoiler log ability thing

* Fix for groups

* Fix for groups

* Fix typo

* Fix hex quest UT support

* Use .get

* UT fixes, classification fixes

* Rename some locations

* Adjust guard house names

* Adjust guard house names

* Rework create_item

* Fix for plando connections

* Rename, add new breakables

* Rename more stuff

* Time to rename them again

* Fix issue with fixed shop + decoupled

* Put in an exception to catch that error in the future

* Update create_item to match main

* Update spoiler log lines for hex abilities

* Burn the signs down

* Bring over the combat logic fix

* Merge in combat logic fix

* Silly static method thing

* Move a few areas to before well instead of east forest

* Add an all_random hidden option for dev stuff

* Port over changes from main

* Fix west courtyard pot regions

* Remove debug prints

* Fix fortress courtyard and beneath the fortress loc groups again

* Add exception handling to deal with duplicate apworlds

* Fix typo

* More missing loc group conversions

* Initial fuse shuffle stuff

* Fix gun missing from combat_items, add new for combat logic cache, very slight refactor of check_combat_reqs to let it do the changeover in a less complicated fashion, fix area being a boss area rather than non-boss area for a check

* Add fuse shuffle logic

* reorder atoll statue rule

* Update traversal reqs

* Remove fuse shuffle from temple door

* Combine rules and option checking

* Add bell shuffle; fix fuse location groups

* Fix portal rules not requiring prayer

* Merge the grass laurels exit grass PR

* Merge in fortress bridge PR

* Do a little clean up

* Fix a regression

* Update after merge

* Some more stuff

* More Silent changes

* Update more info section in game info page

* Fix rules for atoll and swamp fuses

* Precollect cathedral fuse in ER

* actually just make the fuse useful instead of progression

* Add it to the swamp and cath rules too

* Fix cath fuse name

* Minor fixes and edits

* Some UT stuff

* Fix a couple more groups

* Move a bunch of UT stuff to its own file

* Fix up a couple UT things

* Couple minor ER fixes

* Formatting change

* UT poptracker stuff enabled since it's optional in one of the releases

* Add author string to world class

* Adjust local fill option name

* Update ut_stuff to match the PR

* Add exception handling for UT with old apworld

* Fix missing tracker_world

* Remove extra entrance from cath main -> elevator

Entry <-> Elev exists,
Entry <-> Main exists
So no connection is needed between Main and Elev

* Fix so that decoupled doesn't incorrectly use get_portal_info and get_paired_portal

* Fix so that decoupled doesn't incorrectly use get_portal_info and get_paired_portal

* Update for breakables poptracker

* Backup and warnings instead

* Update typing

* Delete old regions and rules, move stuff to logic_helpers and constants

* Delete now much less useful tests

* Fix breakables map tracking

* Add more comments to init

* Add todo to grass.py

* Fix up tests

* Pull out fuse and bell shuffle

* Pull out fuse and bell shuffle

* Update worlds/tunic/options.py

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

* Update worlds/tunic/logic_helpers.py

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

* {} -> () in state functions

* {} -> () in state functions

* Change {} -> () in state functions, use constant for gun

* Remove floating constants in er_data

* Finish hard deprecating FixedShop

* Finish hard deprecating FixedShop

* Fix zig skip showing up in decoupled fixed shop

---------

Co-authored-by: silent-destroyer <osilentdestroyer@gmail.com>
Co-authored-by: Silent <110704408+silent-destroyer@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: qwint <qwint.42@gmail.com>
2025-09-05 00:44:32 +02:00
PoryGone
42ace29db4 Celeste 64: Logic Fixes #5417 2025-09-04 21:53:55 +02:00
qwint
03992c43d9 Docs: update mac install instructions to reflect 3.13 support (#5411) 2025-09-04 16:58:24 +02:00
PoryGone
e342a20fde Celeste (Open World): Post-merge Logic Fix (#5415)
* APWorld Skeleton

* Hair Color Rando and first items

* All interactable items

* Checkpoint Items and Locations

* First pass sample intermediate data

* Bulk of Region/location code

* JSON Data Parser

* New items and Level Item mapping

* Data Parsing fixes and most of 1a data

* 1a complete data and region/location/item creation fixes

* Add Key Location type and ID output

* Add options to slot data

* 1B Level Data

* Added Location logging

* Add Goal Area Options

* 1c Level Data

* Old Site A B C level data

* Key/Binosanity and Hair Length options

* Key Item/Location and Clutter Event handling

* Remove generic 'keys' item

* 3a level data

* 3b and 3c level data

* Chapter 4 level data

* Chapter 5 Logic Data

* Chapter 5 level data

* Trap Support

* Add TrapLink Support

* Chapter 6 A/B/C Level Data

* Add active_levels to slot_data

* Item and Location Name Groups + style cleanups

* Chapter 7 Level Data and Items, Gemsanity option

* Goal Area and victory handling

* Fix slot_data

* Add Core Level Data

* Carsanity

* Farewell Level Data and ID Range Update

* Farewell level data and handling

* Music Shuffle

* Require Cassettes

* Change default trap expiration action to Deaths

* Handle Poetry

* Mod versioning

* Rename folder, general cleanup

* Additional Cleanup

* Handle Farewell Golden Goal when Include Goldens is off

* Better handling of Farewell Golden

* Update Docs

* Beta test bug fixes

* Bump to v1.0.0

* Update Changelog

* Several Logic tweaks

* Update APWorld Version

* Add Celeste (Open World) to README

* Peer review changes

* Logic Fixes:

* Adjust Mirror Temple B Key logic

* Increment APWorld version

* Fix several logic bugs

* Add missing link

* Add Item Name Groups for common alternative item names

* Account for Madeline's post-Celeste hair-dying activities

* Account for ignored member variable and hardcoded color in Celeste codebase

* Add Blue Clouds to the logic of reaching Farewell - intro-02-launch

* Type checking workaround

* Bump version number

* Adjust Setup Guide

* Minor typing fixes

* Logic and PR fixes

* Increment APWorld Version

* Use more world helpers

* Core review

* CODEOWNERS

* Minor logic fix and insert APWorld version into spoiler

* Fix merge error
2025-09-04 03:50:59 +02:00
threeandthreee
3c28db0800 LADX: Drop a marin text option that makes patching fail #5398 2025-09-03 21:02:32 +02:00
qwint
8f88152532 MultiServer: Validate CreateHints status arg #5408 2025-09-03 21:01:56 +02:00
qwint
7a1311984f Docs: Update max py version to 3.13 #5410 2025-09-03 21:00:36 +02:00
Ziktofel
a9f594d6b2 SC2: Remove Starcraft2Client.py as Launcher.py got upgraded to work under Python 3.13 (#5406) 2025-09-02 23:50:29 +02:00
Ziktofel
5f1835c546 SC2: Content update (#5312)
Feature highlights:
- Adds many content to the SC2 game
- Allows custom mission order
- Adds race-swapped missions for build missions (except Epilogue and NCO)
- Allows War Council Nerfs (Protoss units can get pre - War Council State, alternative units get another custom nerf to match the power level of base units)
- Revamps Predator's upgrade tree (never was considered strategically important)
- Adds some units and upgrades
- Locked and excluded items can specify quantity
- Key mode (if opt-in, missions require keys to be unlocked on top of their regular regular requirements
- Victory caches - Victory locations can grant multiple items to the multiworld instead of one 
- The generator is more resilient for generator failures as it validates logic for item excludes
- Fixes the following issues:
  - https://github.com/ArchipelagoMW/Archipelago/issues/3531 
  - https://github.com/ArchipelagoMW/Archipelago/issues/3548
2025-09-02 17:40:58 +02:00
Duck
2359cceb64 AHiT: Add Death Link amnesty options (#4694)
* Add basic death link amnesty option

* Add death wish amnesty option
2025-09-02 05:29:31 +02:00
Rhenaud Dubois
a0a1c5d4c0 Pokemon Emerald: Added Pokemon Gen 3 Adjuster data (#5145)
* Added Pokemon Gen 3 Adjuster data

* Updated extracted data

* Commented out adjuster docs for now

* Replace <b> in the docs markers with **
2025-09-02 01:56:52 +02:00
qwint
14d65fdf28 Docs: Add doc for shared cache (#5129)
* adds doc file describing what the shared cache is, how to use it, and what you can currently expect in it

* Update docs/shared_cache.md

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

---------

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>
2025-09-02 01:54:34 +02:00
qwint
5fd9570368 Docs: Add section about adding Components (#5097)
* kinda driven by wanting to test the labeling change in prod but also components are a weird part of the ecosystem and could use more documentation.

* additional text describing launch/launch_subprocess and their use

* Update docs/adding games.md

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

---------

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>
2025-09-02 01:53:58 +02:00
PoryGone
c753fbff2d Celeste (Open World): Implement New Game (#4937)
* APWorld Skeleton

* Hair Color Rando and first items

* All interactable items

* Checkpoint Items and Locations

* First pass sample intermediate data

* Bulk of Region/location code

* JSON Data Parser

* New items and Level Item mapping

* Data Parsing fixes and most of 1a data

* 1a complete data and region/location/item creation fixes

* Add Key Location type and ID output

* Add options to slot data

* 1B Level Data

* Added Location logging

* Add Goal Area Options

* 1c Level Data

* Old Site A B C level data

* Key/Binosanity and Hair Length options

* Key Item/Location and Clutter Event handling

* Remove generic 'keys' item

* 3a level data

* 3b and 3c level data

* Chapter 4 level data

* Chapter 5 Logic Data

* Chapter 5 level data

* Trap Support

* Add TrapLink Support

* Chapter 6 A/B/C Level Data

* Add active_levels to slot_data

* Item and Location Name Groups + style cleanups

* Chapter 7 Level Data and Items, Gemsanity option

* Goal Area and victory handling

* Fix slot_data

* Add Core Level Data

* Carsanity

* Farewell Level Data and ID Range Update

* Farewell level data and handling

* Music Shuffle

* Require Cassettes

* Change default trap expiration action to Deaths

* Handle Poetry

* Mod versioning

* Rename folder, general cleanup

* Additional Cleanup

* Handle Farewell Golden Goal when Include Goldens is off

* Better handling of Farewell Golden

* Update Docs

* Beta test bug fixes

* Bump to v1.0.0

* Update Changelog

* Several Logic tweaks

* Update APWorld Version

* Add Celeste (Open World) to README

* Peer review changes

* Logic Fixes:

* Adjust Mirror Temple B Key logic

* Increment APWorld version

* Fix several logic bugs

* Add missing link

* Add Item Name Groups for common alternative item names

* Account for Madeline's post-Celeste hair-dying activities

* Account for ignored member variable and hardcoded color in Celeste codebase

* Add Blue Clouds to the logic of reaching Farewell - intro-02-launch

* Type checking workaround

* Bump version number

* Adjust Setup Guide

* Minor typing fixes

* Logic and PR fixes

* Increment APWorld Version

* Use more world helpers

* Core review

* CODEOWNERS
2025-08-31 23:31:09 +02:00
Jérémie Bolduc
cdf7165ab4 Stardew Valley: Use new asserts in tests (#4621)
* changes

* cherry pick stuff

* use newly create methods more

* use new assets to ease readability

* remove unneeded assert

* add assert region adapters

* use new asserts yay

* self review

* self review

* review

* replace parrot express with transportation constant

* bullshit commit again

* revert a bunch of off topic changes

* these changes seems to be on topic

* revert some undesired merge changes

* review imports

* use type instead of instance in some options

* properly return super

* review

* change one str to use a constnat
2025-08-31 16:21:23 +02:00
Etsuna
893acd2f02 Webserver: fix activity_timers for api tracker.py (#5385) 2025-08-31 14:12:32 +02:00
sgrunt
34aaa44b1f Timespinner: add support for spider traps from new client release (#4848)
Co-authored-by: sgrunt <sgrunt1987@gmail.com>
2025-08-31 01:09:22 +02:00
NewSoupVi
f2461a2fea WebHost: Ensure that OptionSets and OptionLists get exported to yaml, even when nothing is selected (#5240)
* Ensure that OptionSets and OptionLists get exported to yaml, even if nothing is selected

* forgot ItemSet and LocationSet

* Make it even less likely for there to be overlap
2025-08-30 22:33:43 +02:00
Justus Lind
bb2ecb8a97 Muse Dash: Change Exception to Option Error and Update to Muse Radio FM106 (#5374)
* Change Exception to OptionError

* Update to Muse Radio FM106.

* Add Scipio's suggestion.

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

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-08-29 17:41:29 +02:00
Rosalie
439be48f36 [TLOZ] Remove deprecated Utils.get_options call, part 2 (#5371)
* Updated to remove deprecated call.

* Removed unused argument.

* Removed errant client calls to Utils.get_options, and fixed call in Rom.py that was passing an argument.
2025-08-27 19:28:42 +02:00
PoryGone
750c8a9810 Stop using get_options (#5341) 2025-08-27 15:21:53 +02:00
lordlou
e11b40c94b [SM, SMZ3] get options deprecation (#5257)
* - 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

* replaced deprecated usage of Utils.get_options with settings.get_settings in SM and SMZ3
2025-08-27 15:21:28 +02:00
Rosalie
be51fb9ba9 [TLOZ] Updated to remove deprecated call. (#5266)
* Updated to remove deprecated call.

* Removed unused argument.
2025-08-27 15:20:51 +02:00
Ishigh1
e1fca86cf8 Core: Improved GER's caching of visited nodes during initialization (#5366)
* Moved the visited update

* Renamed visited to seen
2025-08-27 02:36:47 +02:00
black-sliver
1fa342b085 Core: add python 3.13 support (#5357)
* Core: fix freeze support for py3.13+

Loading Utils now patches multiprocessing.freeze_support()
Utils.freeze_support() is now deprecated

* WebHost: use pony fork on py3.13

* CI: test with py3.13
2025-08-25 17:36:39 +00:00
NewSoupVi
d146d90131 Core: Fix Priority Fill *not* crashing when it should, in cases where there is no deprioritized progression #5363 2025-08-25 17:52:04 +02:00
NewSoupVi
d5bdac02b7 Docs: Add deprioritized to AP API doc (#5355)
Did this on my phone while in the bathroom :)
2025-08-24 02:54:49 +02:00
Exempt-Medic
dfd7cbf0c5 Tests: Standardize World Exclusions, Strengthen LCS Test (#4423) 2025-08-23 18:36:25 -04:00
Aaron Wagener
88a4a589a0 WebHost: add a tracker api endpoint (#1052)
An endpoint from the tracker page.
2025-08-23 08:33:46 +02:00
Duck
bead81b64b Core: Fix get_unique_identifier failing on missing cache folder (#5322) 2025-08-21 07:46:06 +02:00
black-sliver
16d5b453a7 Core: require setuptools>=75 (#5346)
Setuptools 70.3.0 seems to not work for us.
2025-08-19 19:35:50 +02:00
massimilianodelliubaldini
48906de873 Jak and Daxter: fix checks getting lost if player disconnects. (#5280) 2025-08-19 18:08:39 +02:00
Nicholas Saylor
9a64b8c5ce Webhost: Remove showdown.js Remnants (#4984) 2025-08-18 02:48:56 +02:00
Silvris
6ba2b7f8c3 Tests: implement pattern for filtering unittests locally (#5080) 2025-08-18 02:46:48 +02:00
Flit
6f7ca082f2 Docker: use python:3.12-slim-bookworm (#5343) 2025-08-17 20:47:01 +02:00
Faris
eb09be3594 OSRS: Fix UT Integration and Various Gen Failures (#5331) 2025-08-16 17:08:44 -04:00
Fabian Dill
9d654b7e3b Core: drop Python 3.10 (#5324)
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-08-15 18:45:40 +02:00
Doug Hoskisson
8f7fcd4889 Zillion: Move completion_condition Definition Earlier (#5279) 2025-08-15 08:55:11 -04:00
black-sliver
b85887241f CI: update appimagetool hash (#5333) 2025-08-15 12:36:13 +02:00
Fabian Dill
5110676c76 Core: 0.6.4 (#5314) 2025-08-15 11:44:24 +02:00
JaredWeakStrike
0020e6c3d3 KH2: Fix html headers to be markdown (#5305)
* update setup guide

* Update worlds/kh2/docs/setup_en.md

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

* Update worlds/kh2/docs/setup_en.md

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

* Update en_Kingdom Hearts 2.md

---------

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-08-12 23:35:25 +02:00
LiquidCat64
6e6fd0e9bc CV64 and CotM: Correct Archipleago (#5323) 2025-08-12 22:01:29 +02:00
black-sliver
85c26f9740 WebHost: redirect old tutorials to new URL (#5319)
* WebHost: redirect old tutorials to new URL

* WebHost: make comment in tutorial_redirect more accurate
2025-08-12 15:38:22 +00:00
Fabian Dill
9057ce0ce3 WebHost: fix links on sitemap, switch to url_for and add test to prevent future breakage (#5318) 2025-08-12 16:52:34 +02:00
black-sliver
378cc91a4d CI: update appimage runtime (#5315) 2025-08-12 02:41:43 +02:00
qwint
cdde38fdc9 Settings: warn for broken worlds instead of crashing (#4438)
note: i swear the issue was an importerror but i could only get attributeerrors on the getattr() call, maybe we want to check for both?
2025-08-10 17:23:39 +02:00
Adrian Priestley
c34c00baa4 fix(deps): Lock setuptools version to <81 (#5284)
- Update Dockerfile to specify "setuptools<81"
- Modify ModuleUpdate.py to install setuptools with version constraint
2025-08-10 17:09:31 +02:00
Mysteryem
9bd535752e Core: Sort Unreachable Locations Written to the Spoiler (#5269) 2025-08-10 11:03:12 -04:00
Duck
ecb22642af Tests: Handle optional args for get_all_state patch (#5297)
* Make `use_cache` optional

* Pass all kwargs
2025-08-09 00:24:19 +02:00
Exempt-Medic
17ccfdc266 DS3: Don't Create Disabled Locations (#5292) 2025-08-08 15:07:36 -04:00
Scipio Wright
4633f12972 Docs: Use / instead of . for the reference to lttp's options.py (#5300)
* Update options api.md

* o -> O
2025-08-07 20:14:09 +02:00
Silvris
1f6c99635e FF1: fix client breaking other NES games (#5293) 2025-08-05 22:25:11 +02:00
threeandthreee
4e92cac171 LADX: Update Docs (#5290)
* convert ladxr section to markdown, other adjustments
make links clickable
crow icon -> open tracker
adjust for removed sprite sheets
some adjustments in ladxr section for differences in the ap version:
we don't have a casual logic
we don't have stealing options

* fix link, and another correction
2025-08-04 11:46:05 -04:00
Scipio Wright
3b88630b0d TUNIC: Fix zig skip showing up in decoupled + fixed shop #5289 2025-08-04 14:21:58 +02:00
Ishigh1
e6d2d8f455 Core: Added a leading 0 to classification.as_flag #5291 2025-08-04 14:19:51 +02:00
massimilianodelliubaldini
84c2d70d9a Fix regression on 404 redirects 2025-08-03 03:06:42 +00:00
Fabian Dill
d408f7cabc Subnautica: add empty tanks option (#5271) 2025-08-02 21:19:23 +02:00
Fabian Dill
72ae076ce7 WebHost: server render remaining markdown using mistune (#5276)
---------

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-08-02 21:12:58 +02:00
t3hf1gm3nt
277f21db7a The Legend of Zelda: Stepping Down as Maintainer (#5277) 2025-08-02 13:14:24 -04:00
Fabian Dill
9edd55961f LttP: remove sprite download from setup flow & make sprite repo dynamic (#4830) 2025-08-02 01:26:50 +02:00
Fabian Dill
9ad6959559 LttP: move more stuff out of core (#5049)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-08-01 22:30:30 +02:00
qwint
37a9d94865 Core: Purge Multiworld.option_name (#5050) 2025-08-01 22:06:35 +02:00
Jonathan Tan
e8f5bc1c96 TWW: Fix Death Link (#5270) 2025-08-01 14:39:57 -04:00
Wilhelm Schürmann
8bb236411d Various: Make clients wait a second between connects (#5061) 2025-08-01 14:01:18 -04:00
NewSoupVi
332f955159 The Witness: Comply with new test base structure #5265 2025-08-01 01:16:54 +02:00
Fabian Dill
e7131eddc2 Setup: update cert signing process (#5161) 2025-08-01 00:43:43 +02:00
Fabian Dill
8c07a2c930 WebHost: turn module discovery dynamic (#5218) 2025-08-01 00:43:08 +02:00
black-sliver
2fe51d087f CI: also use new appimage tool in release action 2025-07-31 20:49:30 +00:00
Duck
b1f729a970 Core: Remove Checks for Unsupported Versions (#5067)
* Remove redundant version checks/compatibility

* Change windows7 check

* Edit comments

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-07-31 22:33:56 +02:00
Aaron Wagener
754e0a0de4 Core: hard deprecate per_slot_randoms (#3382)
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-07-31 21:42:42 +02:00
josephwhite
7abe7fe304 ALTTP/SNIC/BHC: Stop using Utils.get_settings() (#5239)
* LTTP/SNIC/BHC: Stop using Utils.get_settings()

* SNIClient: use Settings.sni_options
2025-07-31 21:09:00 +02:00
Solidus Snake
8a552e3639 SMZ3: Fix Junk Item Overflow (#5162)
Removed `self.junkItemsNames = [item.Type.name for item in junkItems]` from `create_items` as that was pulling massive amounts of HeartPieces (because they're in junkItems in upstream) to be added if the start_inventory_from_pool was extensive. Getting more than 20 Heart Containers can lead to OHKO situations.

ETank was also removed as a junk item that can be used as filler in the earlier defined list of junk items that AP allows since you should only have 14 in the pool. It's not a problem to have more per se, but you really shouldn't have 27 of them in the pool, either. Ammo and such is much less of a problem to have crazy amounts of.
2025-07-30 07:40:01 -04:00
qwint
743501addc Docs: Remove Settings API Back Compat Section (#5255) 2025-07-29 22:42:55 -04:00
Exempt-Medic
6125e59ce3 Docs: Don't Suggest exclude in create_items (#5256) 2025-07-29 22:33:33 -04:00
Mysteryem
1d8a0b2940 SM: Speed up deepcopy in copy_mixin (#4228) 2025-07-29 22:10:36 -04:00
Nicholas Saylor
2a0ed7faa2 LttP: Remove per_slot_randoms in LttPAdjuster.py (#4898) 2025-07-30 01:18:34 +02:00
BlastSlimey
ad17c7fd21 shapez: Typing Cleanup + Small Docs Rewordings (#5189)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-07-28 11:01:57 -04:00
Doug Hoskisson
4d17366662 Core: fix dangerous mutable default in Fill (#5247)
discussed here https://discord.com/channels/731205301247803413/731214280439103580/1327712564213448775
2025-07-28 15:41:43 +02:00
Doug Hoskisson
5e2702090c Tests: only get __init__.py tests from test directories (#5135) 2025-07-28 03:10:06 +02:00
JKLeckr
f8d1e4edf3 Ignore .github dir in package test (#5098)
Added comments for ignore code
2025-07-28 02:57:19 +02:00
NewSoupVi
04a3f78605 Core: Support inequality operators ("less than") for Choice option string comparisons (#3769)
* add some unit tests to it

* fix

* Update Options.py

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

* Update Options.py

---------

Co-authored-by: qwint <qwint.42@gmail.com>
2025-07-27 23:29:21 +02:00
Yussur Mustafa Oraji
ea1e074083 V6: Allow Secret Lab Music to be Randomized (#4643) 2025-07-27 10:45:48 -04:00
Widowmaker-61
199a6df65e Muse Dash: Adding Option to select Goal Song (#4820)
Co-authored-by: Justus Lind <DeamonHunter@users.noreply.github.com>
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
2025-07-27 07:25:59 +02:00
Doug Hoskisson
c9ebf69e0d Core: MultiData typing (#5071) 2025-07-27 01:27:29 +02:00
Duck
a36e6259f1 Core: Add restricted_dumps helper (#5117)
* Add pickling helper that check unpicklability

* Add test condition and generation error handling

* Fix incorrect call and make imports consistent

* Fix newline padding

* Change PicklingError to directly caused by UnpicklingError

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

* Revert to `pickle.dumps` for decompressed multidata

* Fix import order

* Restore pickle import in main

* Re-add for multidata in Main

* Remove multisave checks

* Update MultiServer.py

* Update customserver.py

---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-07-26 23:01:40 +02:00
Exempt-Medic
de4014f02c Core/Tests: No Locality Changes After generate_early (#4481)
* Change timing of locality option locking

* Update world api.md

* Remove whitespace
2025-07-26 16:30:55 -04:00
Alchav
774457b362 LTTP: Add Missing Crystal Switch Logic (#4638) 2025-07-26 22:25:06 +02:00
threeandthreee
7a8048a8fd LADX: generate without rom (#4278) 2025-07-26 22:16:00 +02:00
qwint
fa49fef695 Core: use patch extension register directly (#4375)
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
2025-07-26 22:13:15 +02:00
threeandthreee
faac2540bf LADX: fix marin text splitting #5225 2025-07-26 19:32:59 +02:00
NewSoupVi
4e1eb78163 MultiServer: Fix LocationScouts with "only_new" broadcasting hints for found locations over and over (#4482)
* Hints PR number 42069

* Make it explicit

* clarify

* oops

* Port the change to CreateHints
2025-07-26 19:30:38 +02:00
Adrian Priestley
46829487d6 fix(docker): Correct copy command to use recursive flag for EnemizerCLI (#5211)
* fix(docker): Correct copy command to use recursive flag for EnemizerCLI
- Changed 'cp' to 'cp -r' to properly copy EnemizerCLI directory

* docs(deployment): Update container deployment documentation
- Specify minimum versions for Docker and Podman
- Add requirement for Docker Buildx plugin
2025-07-26 14:48:39 +00:00
Mysteryem
8fd021e757 Core: Speed up CollectionState sweeping (#3812)
* Sweep events per-player to reduce sweep iterations

By finding all accessible locations per player and then collecting the
items from those locations, if any collected items belong to a different
player, then that player may be able to access more locations the next
time all of their accessible locations are found. This reduces the
number of iterations necessary to sweep through and collect from all
accessible locations.

* Also sweep per-player in MultiWorld.can_beat_game

* Deduplicate code by using sweep_for_events in can_beat_game

sweep_for_events has been modified to be able to return a generator and
to be able to change the set of locations that are filtered out. This
way, the same code can be used by both functions.

* Skip checking locations by assuming each world only logically depends on itself

While this assumption almost always holds true, worlds are allowed to
logically depend on other worlds, so the sweep always double checks at
the end by checking the locations of every world before finishing.

* Fix missed update to CollectionState.collect implementation

Collecting items with prevent_sweep=True (previously event=True) no
longer always returns True, so the return value should now be checked.

* Comment and variable name consistency/clarity

accessible/inaccessible -> reachable/unreachable
final sweep iteration -> extra sweep iteration
maybe_final_sweep -> checking_if_finished

* Apply suggestions from code review

Use Iterator in return type hint instead of Iterable to help indicate that the returned value can only be iterated once.

Be consistent in return statements. Because sweep_for_events can return a value now, the conditional branch that has no intended return value should explicitly return None.

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

* Update terminology from 'event' to 'advancement'

* Add typing overloads for sweep_for_advancements

This makes it so type-checkers and IDEs can see which calls return
`None` and which calls return `Iterator` so that it doesn't complain
about returning an `Iterator` from `sweep_for_events` or about iterating
through `None` in `can_beat_game`.

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

* Update comment for why discard the player after finding their locations

A lack of clarity was brought up in review.

* Update for removed typing import

---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2025-07-26 14:59:35 +02:00
Fabian Dill
a3af953683 WebHost: list unrecognized games as Other in stats (#5236) 2025-07-26 14:12:45 +02:00
Bryce Wilson
f27da5cc78 BizHawkClient: Add command to pass server messages to emulator (#3039) 2025-07-26 12:42:55 +02:00
qwint
23f0b720de CommonClient: update commands to function without local apworld (#3045) 2025-07-26 04:18:36 +02:00
Duck
f66d8e9a61 WebHost: Update some typing in WebHostLib (#5069) 2025-07-26 01:23:39 +02:00
Exempt-Medic
8499c2fd24 Options: Add PlandoItems to Item&Loc Option Group (#5201) 2025-07-25 15:10:31 -04:00
mobby45
ea4c4dcc0c The Wind Waker: Adding French Translation for Guides (#5174)
* Add files via upload

* Delete fr_The Wind Waker.md

* Delete setup_fr.md

* Add files via upload

* Update fr_The Wind Waker.md

* Update fr_The Wind Waker.md

* Update fr_The Wind Waker.md

* Update worlds/tww/docs/fr_The Wind Waker.md

I agree with that okat!

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/fr_The Wind Waker.md

Agreed

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/fr_The Wind Waker.md

agreed!

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/fr_The Wind Waker.md

agreed!

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/fr_The Wind Waker.md

agreed!

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/fr_The Wind Waker.md

forgot to remove that, ok

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/setup_fr.md

agreed!

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/fr_The Wind Waker.md

Okay!

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/setup_fr.md

Agreed

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/setup_fr.md

agreed

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/fr_The Wind Waker.md

agreed

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update fr_The Wind Waker.md

* Update worlds/tww/docs/fr_The Wind Waker.md

okay!

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/fr_The Wind Waker.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/fr_The Wind Waker.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/fr_The Wind Waker.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/fr_The Wind Waker.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/setup_fr.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/setup_fr.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/setup_fr.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/setup_fr.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/setup_fr.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/setup_fr.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/setup_fr.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/setup_fr.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/setup_fr.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update setup_fr.md

* Update setup_fr.md

* Update fr_The Wind Waker.md

Modifying lines

* Update setup_fr.md

Character Limits Update

* Update worlds/tww/docs/setup_fr.md

ok

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/fr_The Wind Waker.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update worlds/tww/docs/fr_The Wind Waker.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update en_The Wind Waker.md

* Update worlds/tww/docs/setup_fr.md

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update __init__.py

* Update __init__.py

* Update worlds/tww/__init__.py

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>

* Update __init__.py

---------

Co-authored-by: Jonathan Tan <tanjo3@users.noreply.github.com>
2025-07-25 21:08:51 +02:00
BadMagic100
88e8e2408b GER: Move EntranceLookup onto ERPlacementState. Improve usefulness of on_connect. (#4904)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-07-25 20:55:22 +02:00
Justus Lind
e5815ae5a2 Muse Dash: Update to Rhythm Master Collab (#5235)
* Rhythm Master Collab

* Deprioritze Music Sheets.

* Oops missed this definition.
2025-07-25 20:47:59 +02:00
black-sliver
387f79ceae setup: Downgrade bundled SNI to 0.0.100 (#5228) 2025-07-25 09:15:34 +02:00
black-sliver
bae1259aba CI: switch to new appimagetool (#5233)
Since this does not have versions anymore, we check the sha256
and require manual intervention if it changed.

TODO: look for a way to do reproducible appimages again.
2025-07-25 09:06:22 +02:00
Adrian Priestley
4ac1d91c16 chore(ci): exclude deployment and Docker files from unit test workflow triggers (#5214)
* chore(ci): exclude deployment and Docker files from unit test workflow triggers
- Modify unittests workflow to ignore changes in deploy directory and Docker-related files
2025-07-24 08:35:13 +02:00
Fabian Dill
81b8f3fc0e Factorio: fix rename of mod file leading to incompatibility with base game (#5219) 2025-07-24 00:01:27 +02:00
MarioManTAW
8541c87c97 Paint: Implement New Game (#4955)
* Paint: Implement New Game

* Add docstring

* Remove unnecessary self.multiworld references

* Implement start_inventory_from_pool

* Convert logic to use LogicMixin

* Add location_exists_with_options function to deduplicate code

* Simplify starting tool creation

* Add Paint to supported games list

* Increment version to 0.4.1

* Update docs to include color selection features

* Fix world attribute definitions

* Fix linting errors

* De-duplicate lists of traps

* Move LogicMixin to __init__.py

* 0.5.0 features - adjustable canvas size increment, updated similarity metric

* Fix OptionError formatting

* Create OptionError when generating single-player game with error-prone settings

* Increment version to 0.5.1

* Update CODEOWNERS

* Update documentation for 0.5.2 client changes

* Simplify region creation

* Add comments describing logic

* Remove unnecessary f-strings

* Remove unused import

* Refactor rules to location class

* Remove unnecessary self.multiworld references

* Update logic to correctly match client-side item caps

---------

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2025-07-23 23:27:50 +02:00
NewSoupVi
0e4314ad1e MultiServer: CreateHints command (Allows clients to hint own items in other worlds) (#4317)
* CreateHint command

* Docs

* oops

* forgot an arg

* Update MultiServer.py

* Add documentation on what happens when the hint already exists but with a different status (nothing)

* Early exit if no locations provided

* Add a clarifying comment to the code as well

* change wording a bit
2025-07-23 13:04:07 +02:00
Flore
6b44f217a3 DS3: Edit the setup docs to be more clear (#4618)
* UPDATE: Dark Souls 3 setup docs to be more clear

* UPDATE: DS3 Setup docs to make offline mode more explicit

* UPDATE: Dark Souls 3 setup docs to be more clear

* UPDATE: DS3 Setup docs to make offline mode more explicit

* EDIT: DS3 setup docs to be up to date
2025-07-22 23:39:07 -04:00
Mysteryem
76760e1bf3 OoT: Fix remove not invalidating cached reachability (#5222)
Collecting an item into a CollectionState without sweeping, finding all
reachable locations, removing that item from the state, and then finding
all reachable locations again could result in more locations being
reachable than before the item was initially collected into the
CollectionState.

This issue was present because OoT was not invalidating its reachable
region caches for the different ages when items were removed from the
CollectionState.

To fix the issue, this PR has updated `OOTWorld.remove()` to invalid its
caches, like how `CollectionState.remove()` invalidates the core
Archipelago caches.
2025-07-23 04:01:47 +02:00
Exempt-Medic
d313a74266 ALttP: Fix pre_fill State Sweeping Too Early (#5215) 2025-07-21 14:53:34 -04:00
Adrian Priestley
a535ca31a8 Dockerfile/Core: Prevent module update during container runtime (#5205)
* fix(env): Prevent module update during requirements processing
- Add environment variable SKIP_REQUIREMENTS_UPDATE check
- Ensure update is skipped if SKIP_REQUIREMENTS_UPDATE is set to true

* squash! fix(env): Prevent module update during requirements processing - Add environment variable SKIP_REQUIREMENTS_UPDATE check - Ensure update is skipped if SKIP_REQUIREMENTS_UPDATE is set to true
2025-07-19 15:48:30 +02:00
Exempt-Medic
da0bb80fb4 Raft: Fix filler_item_types TypeError introduced in #4782 (#5203) 2025-07-18 07:28:05 -04:00
David Carroll
fb9026d12d SMZ3: Add Yaml Options to Slot Data (#5111) 2025-07-17 07:48:55 -04:00
NoiseCrush
4ae36ac727 Super Metroid: Improve Option Descriptions and Add Option Groups (#5100) 2025-07-17 07:46:31 -04:00
Adrian Priestley
ffab3a43fc Docker: Add initial configuration for project (#4419)
* feat(docker): Add initial Docker configuration for project
- Add .dockerignore file to ignore unnecessary files
- Create Dockerfile with basic build and deployment configuration

* feat(docker): Updated Docker configuration for improved security and build efficiency
- Removed sensitive files from .dockerignore
- Moved WORKDIR to /app in Dockerfile
- Added gunicorn==23.0.0 dependency in RUN command
- Created new docker-compose.yml file for service definition

* feat(deployment): Implement containerized deployment configuration

- Add additional environment variables for Python optimization
- Update Dockerfile with new dependencies: eventlet, gevent, tornado
- Create docker-compose.yml and configure services for web and nginx
- Implement example configurations for web host settings and gunicorn
- Establish nginx configuration for reverse proxy
- Remove outdated docker-compose.yml from root directory

* feat(deploy): Introduce Docker Compose configuration for multi-world deployment
- Separate web service into two containers, one for main process and one for gunicorn
- Update container configurations for improved security and maintainability
- Remove unused volumes and network configurations

* docs: Add new documentation for deploying Archipelago using containers
- Document standalone image build and run process
- Include example Docker Compose file for container orchestration
- Provide information on services defined in the `docker-compose.yaml` file
- Mention optional Enemizer feature and Git requirements

* fixup! feat(docker): Updated Docker configuration for improved security and build efficiency - Removed sensitive files from .dockerignore - Moved WORKDIR to /app in Dockerfile - Added gunicorn==23.0.0 dependency in RUN command - Created new docker-compose.yml file for service definition

* feat(deploy): Updated gunicorn configuration example
- Adjusted worker and thread counts
- Switched worker class from sync to gthread
- Changed log level to info
- Added example code snippet for customizing worker count

* fix(deploy): Adjust concurrency settings for self-launch configuration
- Reduce the number of world generators from 8 to 3
- Decrease the number of hosters from 5 to 4

* docs(deploy using containers): Improve readability, fix broken links
- Update links to other documentation pages
- Improve formatting for better readability
- Remove unnecessary sections and files
- Add note about building the image requiring a local copy of ArchipelagoMW source code

* Update deploy/example_config.yaml

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

* Update deploy/example_selflaunch.yaml

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

* Update Dockerfile

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

* Update deploy/example_selflaunch.yaml

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

* fixup! Update Dockerfile

* fix(Dockerfile): Update package installations to use latest versions
- Remove specific version pins for git and libc6-dev
- Ensure compatibility with newer package updates

* feat(ci): Add GitHub Actions workflow for building and publishing Docker images
- Create a new workflow for Docker image build and publish
- Configure triggers for push and pull_request on main branch
- Set up QEMU and Docker Buildx for multi-platform builds
- Implement Docker login for GitHub Container Registry
- Include Docker image metadata extraction and tagging

* feat(healthcheck): Update Dockerfile and docker-compose for health checks
- Add health check for the Webhost service in Dockerfile
- Modify docker-compose to include a placeholder health check for multiworld service
- Standardize comments and remove unnecessary lines

* Revert "feat(ci): Add GitHub Actions workflow for building and publishing Docker images"

This reverts commit 32a51b2726.

* feat(docker): Enhance Dockerfile with Cython build stage
- Add Cython builder stage for compiling speedups
- Update package installation and organization for efficiency
- Improve caching by copying requirements before installing
- Add documentation for rootless Podman

* fixup! feat(docker): Enhance Dockerfile with Cython build stage - Add Cython builder stage for compiling speedups - Update package installation and organization for efficiency - Improve caching by copying requirements before installing - Add documentation for rootless Podman

---------

Co-authored-by: Adrian Priestley <apriestley@gmail.com>
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
Co-authored-by: Adrian Priestley <apriestley@bob.localdomain>
2025-07-17 10:00:57 +02:00
Star Rauchenberger
e38d04c655 Lingo: Fix Painting Gen Failures on Panels Mode Door Shuffle (#5199)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-07-16 23:49:01 -04:00
Aaron Wagener
1923d6b1bc Options: Assert Not All Option in Options.as_dict (#5039)
* Options: forbid worlds just dumping every single option they don't need

* make the equal proper

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-07-16 12:57:11 -04:00
CookieCat
608a38f873 AHIT: Fix Test Fail for assert_not_all_options (#5197) 2025-07-16 12:19:35 -04:00
Jérémie Bolduc
604ab79af9 Stardew Valley: Add walnutsanity prefix to locations (#4934) 2025-07-16 17:57:06 +02:00
qwint
4a43a6ae13 Docs: Clean up SUUID Post #4944 (#5196) 2025-07-16 11:51:34 -04:00
qwint
e9e0861eb7 WebHostLib: Properly Format IDs in API Responses (#4944)
* update the id formatter to use staticmethods to not fake the unused self arg, and then use the formatter for the user session endpoints

* missed an id (ty treble)

* clean up duplicate code

* Update WebHostLib/__init__.py

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

* keep the BaseConverter format

* lol, change all the instances

* revert this

---------

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
2025-07-16 11:34:28 -04:00
Jacob Lewis
477028a025 Dics: Add Webhost API Documententation (#4887)
* capitialization changes

* ditto

* Revert "ditto"

This reverts commit 17cf596735.

* Revert "capitialization changes"

This reverts commit 6fb86c6568.

* full revert and full commit

* Update docs/webhost api.md

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

* Update docs/webhost api.md

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

* Update docs/webhost api.md

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

* Update webhost api.md

* Removed in-devolopment API

* Apply standard capitilization and grammar flow

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

* declarative language

* Apply suggestions from code review

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

* datapackage_checksum clarification, and /datapackage clairfication

* /dp/checksum clarification

* Detailed responces and /generation breakdown

* Update webhost api.md

* Made output anonomous

* Update docs/webhost api.md

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

* Swapped IDs to UUID, and added language around UUID vs SUUID

* Apply suggestions from code review

formatting and grammar

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

* Condensed paragraphs and waterfalled headders

---------

Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-07-16 11:11:07 -04:00
NewSoupVi
b90dcfb041 The Witness: Add Glass Factory Entry Panel as a location in all options #4695 2025-07-16 10:31:12 +02:00
Scipio Wright
1790a389c7 TUNIC: Update Tests Per #4982 (#5191) 2025-07-15 17:04:27 -04:00
Aaron Wagener
deed9de3e7 Core: Don't Cache the get_all_state Result (#4795)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-07-15 16:40:58 -04:00
SunCat
9e748332dc Various Games: Improve Custom Death Link Option Description (#4171)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: LiquidCat64 <74896918+LiquidCat64@users.noreply.github.com>
2025-07-15 16:01:53 -04:00
GreenMarco
749c2435ed Hollow Knight: Add Spanish Language Docs (#5156)
Co-authored-by: qwint <qwint.42@gmail.com>
2025-07-15 15:43:54 -04:00
Danaël V.
6360609980 Witness: Add French and German Setup Documentation (#2527)
Co-authored-by: Lolo <lowgau@gmail.com>
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>
2025-07-15 15:43:20 -04:00
qwint
fed60ca61a Hollow Knight: Explicitly Exclude Palace Items as Filler (#5119) 2025-07-15 15:09:56 -04:00
Fabian Dill
f18f9e2dce Core: increment version (#5194) 2025-07-15 21:04:06 +02:00
Eindall
e1b26bc76f Stardew Valley: Add French Guide (#4697)
Co-authored-by: tmarquis <thomas.marquis@cellance.com>
2025-07-15 15:02:17 -04:00
NewSoupVi
2aada8f683 Core: Add new ItemClassification "deprioritized" which will not be placed on priority locations (if possible) (#4610)
* Add new deprioritized item flag

* 4 retries

* indent

* .

* style

* I think this is nicer

* Nicer

* remove two lines again that I added unnecessarily

* I think this test makes a bit more sense like this

* Idk how to word this lol

* Add progression_deprioritized_skip_balancing bc why not ig

* More text

* Update Fill.py

* Update Fill.py

* I am the big stupid

* Actually collect the other half of progression items into state when filling without them

* More clarity on the descriptions (hopefully)

* visually separate technical description and use cases

* Actually make the call do what the comments say it does
2025-07-15 20:35:27 +02:00
Mysteryem
f9f386fa19 Core: Cache previous swap states to use as the base state to sweep from (#3859)
The previous swap_state can often be used as the base state to create
the next swap_state. This previous swap_state will already have
collected all items in item_pool and is likely to have checked many
locations, meaning that creating the next swap_state from it instead of
from base_state is faster.

From generating with extra code to raise an exception if more than 2
previous swap states were used, and using A Hat in Time and Pokemon
Red/Blue yamls that often result in lots of swapping in progression
fill, I could not get a single seed go through more than 2 previous swap
states. A few worlds' pre-fills do often use more than 2 previous swap
states, notably LADX which sometimes goes through over 20.

Given a 20 player Pokemon Red/Blue multiworld that usually generates in
around 16 or 17 seconds, but on a specific seed that results in 56
swaps, generation went from about 260 seconds before this patch to about
104 seconds after this patch (generated with a meta.yaml to disable
progression balancing and `python -O Generate.py --skip_output`).

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-07-15 20:33:24 +02:00
Mysteryem
507a9a53ef Core: Cleanup: Replace direct calling of dunder methods on objects (#4584)
Calling the dunder method has to:
1. Look up the dunder method for that object/class
2. Bind a new method instance to the object instance
3. Call the method with its arguments
4. Run the appropriate operation on the object

Whereas running the appropriate operation on the object from the start
skips straight to step 4.

Region.Register.__getitem__ is called a lot without #4583. In that case,
generation of 10 template Blasphemous yamls with
`--skip_output --seed 1` and progression balancing disabled went from
19.0s to 18.8s (1.3% reduction in generation duration).

From profiling with `timeit`
```py
        def __getitem__(self, index: int) -> Location:
            return self._list[index]
```
appears to be about twice as fast as the old code:
```py
        def __getitem__(self, index: int) -> Location:
            return self._list.__getitem__(index)
```

Besides this, there is not expected to be any noticeable difference in
performance, and there is not expected to be any difference in semantics
with these changes.

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-07-15 20:33:11 +02:00
NewSoupVi
c1ae637fa7 Core: Crash on full accessibility if there are unreachable locations (Yes, you read that right) #3787 2025-07-15 20:32:53 +02:00
NewSoupVi
f967444ac2 Core: Assert that all the items in the multiworld itempool are actually unplaced at the start of distribute_items_restrictive (#5109)
* Assert at the beginning of distribute items restrictive that no items in the itempool already have locations associated with them

* actual message

* placement

* oops

* Update Fill.py
2025-07-15 20:32:22 +02:00
qwint
c879307b8e CC: Add Assert to Catch Old Datapackage Lookup API (#5131) 2025-07-15 14:30:13 -04:00
qwint
c8ca3e643d Core: Adds Visual Formatting to Option Group Headers in Template Yamls (#5092)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-07-15 14:19:50 -04:00
lordlou
9a648efa70 Super Metroid: Only Put Relevant Options in slot_data (#5192)
* 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

* 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

* reduced slot_data to only what should be needed by PopTracker (for https://github.com/ArchipelagoMW/Archipelago/pull/5039)
2025-07-15 11:48:28 -04:00
qwint
f45410c917 Core: Update UUID handling to be more easily sharable between libraries (#5088)
moves uuid caching to appdata and uuid generation to be a random uuid instead of getnode's hardware address driven identifier and updates docs to point to the shared cache
2025-07-15 07:10:40 +02:00
black-sliver
ec3f168a09 Doc: match statement in style guide (#5187)
* Test: add micro benchmark for match

* Doc: add 'match' to python style guide
2025-07-14 07:22:10 +00:00
Justus Lind
a9b35de7ee Muse Dash: Update song list to Rotaeno Update/7th Anniversary (#5066) 2025-07-12 09:02:49 -04:00
Scipio Wright
125d053b61 TUNIC: Fix missing line for UT stuff #5185 2025-07-12 13:52:02 +02:00
Scipio Wright
585cbf95a6 TUNIC: Add UT Support for Breakables (#5182) 2025-07-12 07:14:34 -04:00
Jérémie Bolduc
909565e5d9 Stardew Valley: Remove Rarecrow Locations from Night Market when Museumsanity is Disabled (#5146) 2025-07-12 07:12:04 -04:00
Exempt-Medic
a79423534c LADX: Update marin.txt (#5178) 2025-07-11 18:44:26 -04:00
NewSoupVi
7a6fb5e35b Revert "Core: Take Counter back out of RestrictedUnpickler" (#5184)
* Revert "Core: Take Counter back out of RestrictedUnpickler #5169"

This reverts commit 95e09c8e2a.

* Update Utils.py
2025-07-11 23:28:18 +02:00
Zach “Phar” Parks
6af34b66fb Various: Remove Rogue Legacy and Clique (#5177)
* Various: Remove Rogue Legacy and Clique

* Remove Clique from setup.py and revert network diagram.md change.

* Try again.

* Update network diagram.md

---------

Co-authored-by: Zach “Phar” Parks <phar@pharware.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-07-11 19:34:46 +02:00
NewSoupVi
2974f7d11f Core: Replace Clique with V6 in unit tests (#5181)
* replace Clique with V6 in unit tests

* no hard mode in V6

* modify regex in copy_world to allow : str

* oops

* I see now

* work around all typing

* there actually needs to be something
2025-07-11 19:27:28 +02:00
Carter Hesterman
edc0c89753 CIV 6: Remove Erroneous Boost Prereqs for Computers Boost (#5134) 2025-07-10 09:10:56 -04:00
axe-y
b1ff55dd06 DLCQ: Fix/Refactor LFoD Start Inventory (#5176) 2025-07-10 08:33:52 -04:00
Remy Jette
f4b5422f66 Factorio: Fix link to world_gen documentation (#5171) 2025-07-07 22:57:55 +02:00
massimilianodelliubaldini
d4ebace99f [Jak and Daxter] Auto Detect Install Path after Game Launcher Update #5152 2025-07-07 19:15:37 +02:00
NewSoupVi
95e09c8e2a Core: Take Counter back out of RestrictedUnpickler #5169 2025-07-07 16:24:35 +02:00
Fabian Dill
4623d59206 Core: ensure slot_data and er_hint_info are only base data types (#5144)
---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2025-07-07 15:51:39 +02:00
Doug Hoskisson
e68b1ad428 CommonClient: fix extra panels added to main_area_container (#5151) 2025-07-06 19:22:02 +02:00
Ixrec
072e2ece15 Docs: 'get_prefill_items' -> 'get_pre_fill_items' (#5167) 2025-07-05 17:01:08 -04:00
agilbert1412
11130037fe Stardew Valley: Fixed luck level requirements for slot machines #5160
# Conflicts:
#	worlds/stardew_valley/data/craftable_data.py
2025-07-03 21:08:36 +02:00
Scipio Wright
ba66ef14cc Update world api.md (#5149) 2025-07-02 14:14:35 +02:00
Jérémie Bolduc
8aacc23882 SDV: Add "Desert Transportation" and "Island Transportation" Item Groups (#5143) 2025-06-28 11:36:09 -04:00
Jonathan Tan
03e5fd3dae TWW: Fix Swords in Swordless Mode (#5137)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-06-28 10:46:37 -04:00
Fly Hyping
da52598c08 Wargroove: Fix Communication Thread (#5125) 2025-06-27 19:42:35 -04:00
Jonathan Tan
52389731eb TWW: Update Preset S7 to S8 (#5138) 2025-06-27 18:46:00 -04:00
LiquidCat64
21864f6f95 CVCotM: Fix Advance Collection ROM (#5132) 2025-06-27 18:25:45 -04:00
DJ-lennart
00f8625280 Civilization VI: Updated setup and info pages (#5123)
* Update setup_en.md

Updated setup instructions for Civilization VI in Archipelago

* Update en_Civilization VI.md

Updated info page for Civilization VI in Archipelago

* Update setup_en.md
2025-06-21 16:31:12 +02:00
James White
c34e29c712 Pokemon RB: Client: Send bounce messages with current map ID (#5121) 2025-06-20 22:52:54 +02:00
palex00
e0ae3359f1 Pokémon RB: Use new link for a new tracker (#5122)
* Update setup_en.md

* Update setup_es.md
2025-06-20 20:55:49 +02:00
Katelyn Gigante
c2666bacd7 core: Don't attempt to write to the inside of an OSX App Bundle (#4380)
* core: Frozen OSX should also use Home Directory

* Use Application Support instead of homedir

* Suggested changes
2025-06-19 18:05:52 +02:00
Aaron Wagener
4eefd9c3ce Kivy: swap from the tab carousel to navigation bar (#4930)
* implement tabs as NavigationBar

* update the underline bar with the screen manager

* remove some unneeded kv

* remove the underline in favor of a full tab highlight

* fix insert transitions

* use on_release instead of on_press

* minor cleanup

* add remove_client_tab and add a caller to the NavigationBar for back compat

* unused imports

* Update kvui.py

---------

Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-06-19 13:39:26 +02:00
Silvris
211456242e KDL3: update to gifting protocol 3 and update settings usage (#4814)
* gift version 3

* update settings usage

* that really has just been broken this entire time

* remove unnecessary print

* Update client.py

* fix random flavor handling

* fix incorrect sender/receiver

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-06-16 13:00:47 -04:00
massimilianodelliubaldini
6f244c4661 Docs: Update Plando Guide and Make it More User Friendly (#4858)
* Make plando guide more user friendly.

* Apply suggestions from code review

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

* Further updates for review.

* Clear search box when filtering by type.

* Forget previous commit name - more code review updates to doc.

* Move link to yaml tutorial.

* Replace STS example with Pokemon RB.

* Use non-key item examples in RB.

* Rooby's code review updates.

* Update worlds/generic/docs/plando_en.md

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

* Update worlds/generic/docs/plando_en.md

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

* Address some more feedback.

* Make Factorio example more accurate.

* Exempt's code review updates (round 4)

* Exempt's code review updates (round 4 + 1)

* Update worlds/generic/docs/plando_en.md

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

* Update worlds/generic/docs/plando_en.md

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

* Update worlds/generic/docs/plando_en.md

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

* Update worlds/generic/docs/plando_en.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>
2025-06-16 12:54:08 -04:00
Exempt-Medic
47bf6d724b Minecraft Removal Cleanup (#5118) 2025-06-16 10:56:47 -04:00
Ixrec
5c710ad032 Docs: Rework the "Events" Section of world api.md (#5012)
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-06-16 08:36:12 -04:00
BlastSlimey
dda5a05cbb shapez: Change Links to Shapesanity Cheat Sheet (#5047) 2025-06-16 08:07:27 -04:00
Natalie Weizenbaum
e0a63e0290 DS3: Link to the Appropriate .NET Runtime for Proton (#5093) 2025-06-16 08:02:06 -04:00
NewSoupVi
9246659589 Make sure ladx removes the same copy of the starting item from the itempool that it's placing (#5110) 2025-06-16 13:49:30 +02:00
digiholic
377cdb84b4 MMBN3: Fixes Generation Errors and General UX Smoothing (#5077)
Co-authored-by: qwint <qwint.42@gmail.com>
2025-06-16 07:47:55 -04:00
KonoTyran
0e759f25fd Remove Minecraft (#4672)
* Remove Minecraft

* remove minecraft

* remove minecraft

* elif -> if

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-06-16 12:31:16 +02:00
qwint
b408bb4f6e Core: Docstring typo on Region.add_exits (#5089)
* doc typo

* Update BaseClasses.py
2025-06-16 02:31:12 +02:00
JusticePS
1356479415 AdventureClient: Replace Utils.get_settings with settings.get_settings #5043 2025-06-16 01:30:45 +02:00
Exempt-Medic
ec5b4e704f Plando Items: Better Warning for Nonexisting Worlds (#5112) 2025-06-14 09:28:02 -04:00
Exempt-Medic
aa9e617510 DS3: Apply Rules to Non-Randomized Locations (#5106) 2025-06-14 09:27:22 -04:00
Exempt-Medic
ecb739ce96 Plando Items: Fix Location Groups Unfolding (#5099) 2025-06-14 09:26:58 -04:00
Exempt-Medic
3b72140435 Shivers: Fix get_pre_fill_items (#5113) 2025-06-14 09:26:22 -04:00
Louis M
27a6770569 Aquaria: Fixing open waters urns not breakable with nature forms logic bug (#5072)
* Fixing open waters urns not breakable with nature forms logic bug

* Using list in comprehension only when useful

* Replacing damaging items by a constant

* Removing comprehension list creating from lambda
2025-06-14 13:17:33 +02:00
NewSoupVi
2ff611167a ALTTP: Fix take_any leaving a placed item in the multiworld itempool #5108 2025-06-14 12:21:25 +02:00
agilbert1412
e83e178b63 Stardew Valley: Fix 3 Logic Issues (#5094)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-06-13 20:29:23 -04:00
Exempt-Medic
068a757373 Item Plando: Fix count value (#5101) 2025-06-13 20:29:06 -04:00
PoryGone
0ad4527719 SA2B: Logic Fixes (#5095)
- Fixed King Boom Boo being able to appear in multiple boss gates
- `Final Rush - 16 Animals (Expert)` no longer requires `Sonic - Bounce Bracelet`
- `Dry Lagoon - 5 (Standard)` now requires `Rouge - Pick Nails`
- `Sand Ocean - Extra Life Box 2 (Standard/Hard/Expert)` no longer requires `Eggman - Jet Engine`
- `Security Hall - 8 Animals (Expert)` no longer requires `Rouge - Pick Nails`
- `Sky Rail - Item Box 8 (Standard)` now requires `Shadow - Air Shoes` and `Shadow - Mystic Melody`
- `Cosmic Wall - Chao Key 1 (Standard/Hard/Expert)` no longer requires `Eggman - Mystic Melody`
- `Cannon's Core - Pipe 2 (Expert)` no longer requires `Tails - Booster`
- `Cannon's Core - Gold Beetle` no longer requires `Tails - Booster` nor `Knuckles - Hammer Gloves`
2025-06-13 22:01:19 +02:00
qwint
8c6327d024 LTTP/SDV: use .name when appropriate in subtests (#5107) 2025-06-13 21:56:09 +02:00
qwint
aecbb2ab02 fix saving princess's use of subprocess helpers (#5103) 2025-06-13 12:28:58 +02:00
JaredWeakStrike
52b11083fe KH2: Raise Exception for Misusing DonaldGoofyStatsanity Option (#4710)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-06-11 15:52:47 -04:00
BadMagic100
a8c87ce54b CI: Add GH_REPO environment variable to labeler (#5081) 2025-06-10 05:55:40 +02:00
JaredWeakStrike
ddb3240591 KH2: Give warning when client has cached locations (#5000)
* a

* disconnect when connect to wrong slot

* connection to the wrong seed fix

* seed_name is always none
2025-06-09 14:58:08 +02:00
qwint
f25ef639f2 Launcher: Fix Cli Components when installed to a directory with a space (#5091) 2025-06-09 00:43:23 +02:00
BlastSlimey
ab7d3ce4aa shapez: Remove preset unittests #5086 2025-06-06 00:05:53 +02:00
Jarno
50db922cef Timespinner: Fixed generation error because of timezone locking (#5084)
* Fixed generation error because of timezone locking

* Refactored logic + prevent excluding warps when unchained keys in on
2025-06-05 15:05:00 +02:00
Ehseezed
a2708edc37 Timespinner: Fix Castle Ramparts Region Connection #5082
Co-authored-by: ehseezed <Ehseezed@users.noreply.github.com>
2025-06-04 19:51:08 +02:00
Exempt-Medic
603a5005e2 DS3: Fix Non-Crow Itemlinking and Mark Aldrich Ruby and Twin Dragon Greatshield As Missable (#4510)
* Fix Branch (Not Crow)

* Oops

* Mark Aldrich Ruby as missable

* Expand comment

* Short circuit

* Mark Twin Dragon Greatshield as missable

* Add missable cause
2025-06-03 08:49:10 -04:00
Fabian Dill
b4f68bce76 Factorio: revamp args parsing and passing (#5036) 2025-06-03 13:49:44 +02:00
Scipio Wright
a76cec1539 TUNIC: Fix decoupled ER + ladder storage making invalid entrances #5075 2025-06-03 12:51:06 +02:00
black-sliver
694e6bcae3 Launcher/Utils: reset LD_LIBRARY_PATH for system EXEs (#5022) 2025-06-03 10:42:37 +00:00
black-sliver
b85b18cf5f SoE: remove outdated info from guide (#5064)
The client does not depend on Animation Frame anymore, so it can be backgrounded.
2025-06-02 16:39:42 +00:00
Mysteryem
04c707f874 DKC3: Add missing indirect conditions (#5073)
A couple of Entrance access rules were checking for being able to reach
a Location, but a Location first checks for being able to reach its
parent Region, so it needs to be registered that access to that parent
Region can give access to the Entrance.
2025-06-02 18:06:54 +02:00
Exempt-Medic
99142fd662 Plando Items: Fix count with empty locations/location #5040 2025-06-02 18:01:21 +02:00
Mysteryem
0c5cb17d96 DLCQuest: Add missing indirect conditions (#5074)
The `Behind Rocks` and `Pickaxe Hard Cave` Entrances require being able
to reach the `Cut Content` region, but no indirect conditions were being
registered for this region.

The `set_lfod_self_obtained_items_rules` function was also using a
`world` parameter that was actually expecting a `MultiWorld` instance,
so I have renamed it for clarity and updated the function to use
`world.get_entrance()` rather than `multiworld.get_entrance()`.

Much of the rest of the file passes `MultiWorld` instances to `world`
parameters, but fixing all of these is out of the scope of the changes
in this patch, so has not been included.
2025-06-02 17:56:11 +02:00
qwint
cabde313b5 WebHost: Use expected APPlayerContainer manifest location directly when ingesting them #4754 2025-06-02 17:53:57 +02:00
qwint
8f68bb342d Core and Various Worlds: define patch_file_ending to APPlayerContainer (#5058)
* move to playercontainer

* moves patch_file_ending handling to APPlayerContainer and updates the worlds using it to define their extensions

* give oot a patch_file_ending as well
2025-06-02 17:53:18 +02:00
Jérémie Bolduc
fab75d3a32 Stardew Valley: Fix Wizard Tower and Entrance Randomizer Softlocks (#4631)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-05-31 07:57:42 -04:00
massimilianodelliubaldini
d19bf98dc4 Jak and Daxter: Post-merge Polish (#5031)
- Cleans up a few missed references in the setup guide.
- Refactors Options class to use metaclass and decorators to enforce friendly limits on multiple levels.    
  - Templates generated from the website, even ones with `random` should not fail generation because the website will only allow values inside the friendly limits. 
  - _Uploaded_ yamls to the website with `random`, should also now respect friendly limits without the need for `random-range` shenanigans.
  - _Uploaded_ yamls to the website, or yamls that are used to generate locally, that have hard-defined values outside the friendly limits, will be clamped/dragged/massaged into those limits (with logged warnings).
- Removed an early completion goal that was playing havoc with fill. Not enough people seem to use this goal, so its loss will not be mourned.
2025-05-30 16:31:00 +02:00
sgrunt
b0f41c0360 Timespinner: Fix Connection Logic from Maw Cave Entrance to Maw (#4831)
Co-authored-by: sgrunt <sgrunt1987@gmail.com>
2025-05-28 20:40:24 -04:00
sgrunt
6ebd60feaa Timespinner: Fix Logic Error with Risky Warp to Emperor's Tower and Lab Access (#4784)
Co-authored-by: sgrunt <sgrunt1987@gmail.com>
2025-05-28 20:37:39 -04:00
Jonathan Tan
dd6007b309 TWW: Remove unnecessary items from slot data (#5045) 2025-05-29 00:27:03 +02:00
Ehseezed
fde203379d Timespinner: Fix Logic (#4803)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-05-28 15:04:57 -04:00
LiquidCat64
fcb3efee01 CVCotM: Add Nerf Roc Wing to Slot Data and HoD Max Ups to other_game_item_appearances (#5051) 2025-05-28 10:47:24 -04:00
black-sliver
19a21099ed Webhost: update Flask to 3.1.1 (#5052) 2025-05-27 16:21:43 +00:00
Jonathan Tan
20ca7e71c7 TWW: Update patch class (#5046) 2025-05-27 07:57:20 +02:00
ScootyPuffJr1
002202ff5f Update OOT Guides (#5041)
* Update OOT Guides

* Minor update per review
2025-05-26 07:25:39 +00:00
FlitPix
32487137e8 Core: Add descriptions to Components (#4849)
* Add descriptions to components

* Adhere to style guide

* Tweak BHC wording

* Trim Open Patch description

* Update text client description for consistency

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

* Remove newlines

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-05-25 17:17:30 -04:00
LiquidCat64
f327ab30a6 CV64: Allow Holding Z to Use the Regular Shimmy Speed (#4730)
* Add the shimmy modifier hack.

* Update the Increase Shimmy Speed option description.

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-05-25 05:20:25 -04:00
agilbert1412
e7545cbc28 SDV: Fixed Region for two Parrot Locations (#5042) 2025-05-24 17:59:55 -04:00
NewSoupVi
eba757d2cd Raft: Implement get_filler_item_name and refactor filler item code a bit (#4782)
* refactor filler item creation for Raft, implement get_filler_item_name

* wrong indent

* Update worlds/raft/__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-05-24 23:02:27 +02:00
Star Rauchenberger
4119763e23 Lingo: Fix The Bearer's Pilgrimage Logic (#5005) 2025-05-24 09:35:06 -04:00
Jonathan Tan
e830a6d6f5 TWW: Only add Filler for Excluded Locations Which are Progress Locations (#4993)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-05-24 09:17:54 -04:00
Bryce Wilson
704cd97f21 BizHawkClient: Fix script to list all cores instead of explicit mapping (#5033) 2025-05-24 07:33:01 +02:00
agilbert1412
47a0dd696f Stardew Valley: Added moss to statue of blessings recipe (#5038) 2025-05-24 07:28:25 +02:00
Jérémie Bolduc
c64791e3a8 Stardew Valley: Replace current naive entrance rando with GER (#4624) 2025-05-24 07:15:41 +02:00
Aaron Wagener
e82d50a3c5 The Messenger: more generous portal validation (#5011)
* The Messenger: more generous portal validation

* remove the while and just go for 20 attempts. hopefully that's enough
2025-05-24 00:13:34 +02:00
qwint
0a7aa9e3e2 Launcher: skip launcher gui when opening webhost list with no game handlers (#4888)
* calc relevant components before opening the launcher app so it can be skipped for text client only uri launches

* generically passthrough the url arg

* Apply suggestions from code review

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

* flip if not else

* Update Launcher.py

* pluralize

---------

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
2025-05-24 00:02:50 +02:00
NewSoupVi
13ca134d12 Core: Fix a playthrough crash when a world uses "placement based logic" (#3915)
* Fix playthrough

* oops

* oops 2

* I don't like this

* that should do it

* Update BaseClasses.py

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

* Update BaseClasses.py

---------

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2025-05-23 23:47:21 +02:00
Jérémie Bolduc
8671e9a391 Stardew Valley: Make animal catalog logically year 2 (#5032) 2025-05-23 19:52:47 +00:00
BlastSlimey
a7de89f45c shapez: Add game to README and CODEOWNERS (#5034)
* Aktualisieren von README.md

* Aktualisieren von CODEOWNERS
2025-05-23 19:41:27 +00:00
black-sliver
e9f51e3302 Linux: avoid adding cwd to LD_LIBRARY_PATH (#5029)
When LD_LIBRARY_PATH is not set, the old code would also add
the current working directory to LD_LIBRARY_PATH, which is bad.
2025-05-23 19:26:37 +00:00
Aaron Wagener
5491f8c459 Core: Make get_all_state Sweeping Optional (#4828) 2025-05-22 22:28:56 -04:00
Fabian Dill
de71677208 Core: only raise min_client_version for new gens (#4896) 2025-05-22 21:30:30 +02:00
Nicholas Saylor
653ee2b625 Docs: Update Snippets to Modern Type Hints (#4987) 2025-05-22 15:00:30 -04:00
qwint
62694b1ce7 Launcher: Fix on File Drop Error Message (#5026) 2025-05-22 11:37:23 -04:00
Rosalie
9c0ad2b825 FF1: Bizhawk Client and APWorld Support (#4448)
Co-authored-by: beauxq <beauxq@yahoo.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-05-22 11:35:38 -04:00
qwint
88b529593f CommonClient: Add docs for Attributes (#5003)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-05-22 11:08:15 -04:00
agilbert1412
0351698ef7 SDV: Fixed Import bases (#5025) 2025-05-22 11:07:57 -04:00
Jérémie Bolduc
984df75f83 Stardew Valley: Move and Rework Monstersanity Tests (#4911) 2025-05-22 10:24:04 -04:00
Mysteryem
402a8fb967 AHiT: Add Dweller Mask Requirement to Normal Logic Rush Hour (#4499) 2025-05-22 10:16:16 -04:00
Aaron Wagener
45e3027f81 The Messenger: Add a Component Icon and Description (#4850)
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-05-22 10:06:44 -04:00
Aaron Wagener
1d655a07cd Core: Add State add/remove/set Helpers (#4845) 2025-05-22 09:46:33 -04:00
FlitPix
c5e768ffe3 Minecraft: Stop Using Utils.get_options (#4879) 2025-05-22 09:42:54 -04:00
Aaron Wagener
8cc6f10634 The Messenger: Swap Options Docstrings to use rst, Add Option Groups (#4913)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-05-22 09:40:50 -04:00
Aaron Wagener
aeac83d643 Generate: Don't Force Player Name for Weights Files (#4943) 2025-05-22 09:29:24 -04:00
qwint
95efcf6803 Tests: Create CollectionState after MultiWorld.worlds (#4949) 2025-05-22 09:27:18 -04:00
josephwhite
44a78cc821 OoT: Stop Using Utils.get_options (#4957) 2025-05-22 09:26:28 -04:00
Scipio Wright
e0918a7a89 TUNIC: Move some UT stuff out of init, put in UT poptracker integration support (#4967) 2025-05-22 09:24:50 -04:00
qwint
b52310f641 Wargroove: Cleanup script_name Component in LauncherComponents (#5021) 2025-05-22 09:12:28 -04:00
Silvris
e3219ba452 WebHost: allow APPlayerContainers from "custom" worlds to be displayed in rooms (#4981)
Gives WebHost the ability to verify that a patch file is an APPlayerContainer (defined by #4331 as a APContainer containing the "player" field), and allowed it to display any patch file that it can verify is an APPlayerContainer.
2025-05-22 09:47:48 +02:00
Fly Hyping
7079c17a0f Wargroove: apworld doc fixes (#5023) 2025-05-22 09:11:34 +02:00
black-sliver
3b8450036a core: don't reconfigure stdout if it's fake (#5020) 2025-05-22 01:22:55 +02:00
Fly Hyping
defdf34e60 Wargroove: apworld (#4764)
- Players and AI can sacrifice their own units and upload them to the multiworld.
- Players and AI can summon random units from the multiworld.
- Has 4 new separate options for how many sacrifices and summons either the player or the AI can make per level attempt.
- New /sacrifice_summon command to toggle sacrifices and summons on/off. Useful if the AI makes a level impossible with their summons.
- Linux Support.
- Is an apworld now.


---------

Co-authored-by: Raspberry Floof <raspberry@rosenthalcastle.org>
Co-authored-by: KScl <ks@rosenthalcastle.org>
Co-authored-by: Abigail Fox <Raspberryfloof@users.noreply.github.com>
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2025-05-22 01:00:45 +02:00
Fabian Dill
6827368e60 Core: generate templates faster and "cleaner" (#5019) 2025-05-22 00:45:49 +02:00
Katelyn Gigante
a409167f64 core: Reconfigure stdout to utf8 (#5017) 2025-05-21 20:27:03 +02:00
Natalie Weizenbaum
a076b9257d DS3: Don't make unrandomized items into events (#5018)
The DS3 static randomizer uses the relative ordering of location names
to map between Archipelago's notion of location IDs and the static
randomizer's. Treating unrandomized locations as excluded can break this
behavior by removing some locations from the list, causing further
locations to be incorrectly assigned.

The only reason this wasn't a bigger problem up to this point was that
location order only matters on a per-region and per-item basis. That
means this only causes problems in practice when a single region has
multiple locations with the same default item, and some of those
locations are randomized while others are not. Since exclusions (and
thus randomization) are usually done based on item types, we managed to
dodge this bullet for a long time.
2025-05-21 18:59:04 +02:00
Sunny Bat
7e772b4ee9 Raft: Small Raft doc update, bugfix (#5008)
* Small doc touchups

* Advanced Scarecrow progressive

* Add period to doc

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>

---------

Co-authored-by: Duck <31627079+duckboycool@users.noreply.github.com>
2025-05-21 18:12:37 +02:00
Alchav
955a86803f Super Mario Land 2: Implement New Game (#2730)
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: alchav <alchav@jalchavware.com>
2025-05-21 11:02:30 -04:00
BlastSlimey
d5bacaba63 shapez: Implement New Game (#3960)
Adds shapez as a supported game in AP.
2025-05-21 14:30:39 +02:00
massimilianodelliubaldini
3069deb019 Jak and Daxter: Implement New Game (#3291)
* Jak 1: Initial commit: Cell Locations, Items, and Regions modeled.

* Jak 1: Wrote Regions, Rules, init. Untested.

* Jak 1: Fixed mistakes, need better understanding of Entrances.

* Jak 1: Fixed bugs, refactored Regions, added missing Special Checks. First spoiler log generated.

* Jak 1: Add Scout Fly Locations, code and style cleanup.

* Jak 1: Add Scout Flies to Regions.

* Jak 1: Add version info.

* Jak 1: Reduced code smell.

* Jak 1: Fixed UT bugs, added Free The Sages as Locations.

* Jak 1: Refactor ID scheme to better fit game's scheme. Add more subregions and rules, but still missing one-way Entrances.

* Jak 1: Add some one-ways, adjust scout fly offset.

* Jak 1: Found Scout Fly ID's for first 4 maps.

* Jak 1: Add more scout fly ID's, refactor game/AP ID translation for easier reading and code reuse.

* Jak 1: Fixed a few things. Four maps to go.

* Jak 1: Last of the scout flies mapped!

* Jak 1: simplify citadel sages logic.

* Jak 1: WebWorld setup, some documentation.

* Jak 1: Initial checkin of Client. Removed the colon from the game name.

* Jak 1: Refactored client into components, working on async communication between the client and the game.

* Jak 1: In tandem with new ArchipelaGOAL memory structure, define read_memory.

* Jak 1: There's magic in the air...

* Jak 1: Fixed bug translating scout fly ID's.

* Jak 1: Make the REPL a little more verbose, easier to debug.

* Jak 1: Did you know Snowy Mountain had such specific unlock requirements? I didn't.

* Jak 1: Update Documentation.

* Jak 1: Simplify user interaction with agents, make process more robust/less dependent on order of ops.

* Jak 1: Simplified startup process, updated docs, prayed.

* Jak 1: quick fix to settings.

* Jak and Daxter: Implement New Game (#1)

* Jak 1: Initial commit: Cell Locations, Items, and Regions modeled.

* Jak 1: Wrote Regions, Rules, init. Untested.

* Jak 1: Fixed mistakes, need better understanding of Entrances.

* Jak 1: Fixed bugs, refactored Regions, added missing Special Checks. First spoiler log generated.

* Jak 1: Add Scout Fly Locations, code and style cleanup.

* Jak 1: Add Scout Flies to Regions.

* Jak 1: Add version info.

* Jak 1: Reduced code smell.

* Jak 1: Fixed UT bugs, added Free The Sages as Locations.

* Jak 1: Refactor ID scheme to better fit game's scheme. Add more subregions and rules, but still missing one-way Entrances.

* Jak 1: Add some one-ways, adjust scout fly offset.

* Jak 1: Found Scout Fly ID's for first 4 maps.

* Jak 1: Add more scout fly ID's, refactor game/AP ID translation for easier reading and code reuse.

* Jak 1: Fixed a few things. Four maps to go.

* Jak 1: Last of the scout flies mapped!

* Jak 1: simplify citadel sages logic.

* Jak 1: WebWorld setup, some documentation.

* Jak 1: Initial checkin of Client. Removed the colon from the game name.

* Jak 1: Refactored client into components, working on async communication between the client and the game.

* Jak 1: In tandem with new ArchipelaGOAL memory structure, define read_memory.

* Jak 1: There's magic in the air...

* Jak 1: Fixed bug translating scout fly ID's.

* Jak 1: Make the REPL a little more verbose, easier to debug.

* Jak 1: Did you know Snowy Mountain had such specific unlock requirements? I didn't.

* Jak 1: Update Documentation.

* Jak 1: Simplify user interaction with agents, make process more robust/less dependent on order of ops.

* Jak 1: Simplified startup process, updated docs, prayed.

* Jak 1: quick fix to settings.

* Jak and Daxter: Genericize Items, Update Scout Fly logic, Add Victory Condition. (#3)

* Jak 1: Update to 0.4.6. Decouple locations from items, support filler items.

* Jak 1: Total revamp of Items. This is where everything broke.

* Jak 1: Decouple 7 scout fly checks from normal checks, update regions/rules for orb counts/traders.

* Jak 1: correct regions/rules, account for sequential oracle/miner locations.

* Jak 1: make nicer strings.

* Jak 1: Add logic for finished game. First full run complete!

* Jak 1: update group names.

* Jak and Daxter - Gondola, Pontoons, Rules, Regions, and Client Update

* Jak 1: Overhaul of regions, rules, and special locations. Updated game info page.

* Jak 1: Preparations for Alpha. Reintroducing automatic startup in client. Updating docs, readme, codeowners.

* Alpha Updates (#15)

* Jak 1: Consolidate client into apworld, create launcher icon, improve setup docs.

* Jak 1: Update setup guide.

* Jak 1: Load title screen, save states of in/outboxes.

* Logging Update (#16)

* Jak 1: Separate info and debug logs.

* Jak 1: Update world info to refer to Archipelago Options menu.

* Deathlink (#18)

* Jak 1: Implement Deathlink. TODO: make it optional...

* Jak 1: Issue a proper send-event for deathlink deaths.

* Jak 1: Added cause of death to deathlink, fixed typo.

* Jak 1: Make Deathlink toggleable.

* Jak 1: Added player name to death text, added zoomer/flut/fishing text, simplified GOAL call for deathlink.

* Jak 1: Fix death text in client logger.

* Move Randomizer (#26)

* Finally remove debug-segment text, update Python imports to relative paths.

* HUGE refactor to Regions/Rules to support move rando, first hub area coded.

* More refactoring.

* Another refactor - may squash.

* Fix some Rules, reuse some code by returning key regions from build_regions.

* More regions added. A couple of TODOs.

* Fixed trade logic, added LPC regions.

* Added Spider, Snowy, Boggy. Fixed Misty's orbs.

* Fix circular import, assert orb counts per level, fix a few naming errors.

* Citadel added, missing locs and connections fixed. First move rando seed generated.

* Add Move Rando to Options class.

* Fixed rules for prerequisite moves.

* Implement client functionality for move rando, add blurbs to game info page.

* Fix wrong address for cache checks.

* Fix byte alignment of offsets, refactor read_memory for better code reuse.

* Refactor memory offsets and add some unit tests.

* Make green eco the filler item, also define a maximum ID. Fix Boggy tether locations.

* Move rando fixes (#29)

* Fix virtual regions in Snowy. Fix some GMC problems.

* Fix Deathlink on sunken slides.

* Removed unncessary code causing build failure.

* Orbsanity (#32)

* My big dumb shortcut: a 2000 item array.

* A better idea: bundle orbs as a numerical option and make array variable size.

* Have Item/Region generation respect the chosen Orbsanity bundle size. Fix trade logic.

* Separate Global/Local Orbsanity options. TODO - re-introduce orb factory for per-level option.

* Per-level Orbsanity implemented w/ orb bundle factory.

* Implement Orbsanity for client, fix some things up for regions.

* Fix location name/id mappings.

* Fix client orb collection on connection.

* Fix minor Deathlink bug, add Update instructions.

* Finishing Touches (#36)

* Set up connector level thresholds, completion goal choices.

* Send AP sender/recipient info to game via client.

* Slight refactors.

* Refactor option checking, add DataStorage handling of traded orbs.

* Update instructions to change order of load/connect.

* Add Option check to ensure enough Locations exist for Cell Count thresholds. Fix Final Door region.

* Need some height move to get LPC sunken chamber cell.

* Rename completion_condition to jak_completion_condition (#41)

* The Afterparty (#42)

* Fixes to Jak client, rules, options, and more.

* Post-rebase fixes.

* Remove orbsanity reset code, optimize game text in client.

* More game text optimization.

* Added more specific troubleshooting/setup instructions.

* Add known issue about large releases taking time. (Dodge 6,666th commit.)

* Remove "Bundle of", Add location name groups, set better default RootDirectory for new players.

* Make orb trade amounts configurable, make orbsanity defaults more reasonable.

* Add HUD info to doc.

* Exempt's Code Review Updates (#43)

* Round 1 of code review updates, the easy stuff.

* Factor options checking away from region/rule creation.

* Code review updates round 2, more complex stuff.

* Code review updates round 3: the mental health annihilator

* Code review updates part 4: redemption.

* More code review feedback, simplifying code, etc.

* Added a host.yaml option to override friendly limits, plus a couple of code review updates.

* Added singleplayer limits, player names to enforcement rules.

* Updated friendly limits to be more strict, optimized recalculate logic.

* Today's the big day Jak: updates docs for mod support in OpenGOAL Launcher

* Rearranged and clarified some instructions, ADDED PATH-SPACE FIX TO CLIENT.

* Fix deathlink reset stalls on a busy client. (#47)

* Jak & Daxter Client : queue game text messages to get items faster during release (#48)

* queue game text messages to write them during the main_tick function and empty the message queue faster during release

* wrap comment for code style character limit

Co-authored-by: massimilianodelliubaldini <8584296+massimilianodelliubaldini@users.noreply.github.com>

* remove useless blank line

Co-authored-by: massimilianodelliubaldini <8584296+massimilianodelliubaldini@users.noreply.github.com>

* whitespace code style

Co-authored-by: massimilianodelliubaldini <8584296+massimilianodelliubaldini@users.noreply.github.com>

* Move JsonMessageData dataclass outside of ReplClient class for code clarity

---------

Co-authored-by: massimilianodelliubaldini <8584296+massimilianodelliubaldini@users.noreply.github.com>

* Item Classifications (and REPL fixes) (#49)

* Changes to item classifications

* Bugfixes to power cell thresholds.

* Fix bugs in item_type_helper.

* Refactor 100 cell door to pass unit tests.

* Quick fix to ReplClient.

* Not so quick fix to ReplClient.

* Display friendly limits in options tooltips.

* Use math.ceil like a normal person.

* Missed a space.

* Fix non-accessibility due to bad orb calculation.

* Updated documentation.

* More Options, More Docs, More Tests (#51)

* Reorder cell counts, require punch for Klaww.

* Friendlier friendly friendlies.

* Removed custom_worlds references from docs/setup guide, focused OpenGOAL Launcher language.

* Increased breadth of unit tests.

* Clean imports of unit tests.

* Create OptionGroups.

* Fix region rule bug with Punch for Klaww.

* Include Punch For Klaww in slot data.

* Update worlds/jakanddaxter/__init__.py

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

* Temper and Harden Text Client (#52)

* Provide config path so OpenGOAL can use mod-specific saves and settings.

* Add versioning to MemoryReader. Harden the client against user errors.

* Updated comments.

* Add Deathlink as a "statement of intent" to the YAML. Small updates to client.

* Revert deathlink changes.

* Update error message.

* Added color markup to log messages printed in text client.

* Separate loggers by agent, write markup to GUI and non-markup to disk simultaneously.

* Refactor MemoryReader callbacks from main_tick to constructor.

* Make callback names more... informative.

* Give users explicit instructions in error messages.

* Stellar Messaging (#54)

* Use new ap-messenger functions for text writing.

* Remove Powershell requirement, bump memory version to 3.

* Error message update w/ instructions for game crash.

* Create no console window for gk.

* ISO Data Enhancement (#58)

* Add iso-path as argument to GOAL compiler.

# Conflicts:
#	worlds/jakanddaxter/Client.py

* More resilient handling of iso_path.

* Fixed scout fly ID mismatches.

* Corrected iso_data subpath.

* Update memory version to 4.

* Docs update for iso_data.

* Auto Detect OpenGOAL Install (#63)

* Auto detect OpenGOAL install path. Also fix Deathlink on server connection.

* Updated docs, add instructions to error messages.

* Slight tweak to error text.

* J&D : add per region location groups (#64)

* add per region power cells location group

* add per region scout flies location group

* add per zone orb bundle groups
(I'm not particularly happy about this code, but I figured doing it this way was the point of least friction/duplication)

* guess who forgot 9 very important characters in each line of the last commit

* Rearrange location group names, quick fix to client error handling.

* Fix pycharm warnings.

* Fix more pycharm warnings.

* Light cleanup: fix icons, add bug report page, remove py 3.8 code.

* Update worlds/jakanddaxter/Options.py

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

* Update worlds/jakanddaxter/Options.py

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

* Update worlds/jakanddaxter/Options.py

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

* Update worlds/jakanddaxter/Options.py

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

* Code review updates on comments, tooltips, and type hints.

* Update type hint for lists in regions.

* Missed todo removal.

* More type hint updates.

* Small region updates for location accessibility, small updates to world guide and README.md.

* Add GMC scout fly location group.

* Improved sanitization of game text.

* Traps 2 (#70)

* Add trap items, relevant options, and citadel orb caches.

* Update REPL to send traps to game.

* Fix item counter.

* Allow player to select which traps to use.

* Fix host.yaml doc strings, ap-setup-options typing, bump memory version to 5.

* Alter some trap names.

* Update world doc.

* Add health trap.

* Added 3 more trap types.

* Protect against empty trap list.

* Reword traps paragraph in world doc.

* Another update to trap paragraph.

* Concisify trap option docstring.

* Timestamp on game log file.

* Update client to handle waiting on title screen.

* Send slot name and seed to game.

* Use self.random instead.

* Update setup doc for new title screen.

* Quick clarification of orb caches in world doc.

* Sanitize slot info earlier.

* Added to and improved unit tests.

* Light cleanup on world.

* Optimizations to movement rules, docs: known issues update.

* Quick fixes for beta 0.5.0 release: template options and LPC logic.

* Quick fix to spoiler counts.

* Reorganize world guide for faster navigation.

* Fix links.

* Update HUD section.

* Found a way to render apostrophes in item names.

* March Refactors (#77)

* Reorg imports, small fix to Rock Village movement.

* Fix wait-on-title message never going to ready message.

* Colorama init fix.

* Swap trap list for a dictionary of trap weights.

* The more laws, the less justice.

* Quick readability update.

* Have memory reader provide instructions for slow booting games.

* Revert some things.

* Update setup_en.md

* Update HUD mode lingo for combined msgs.

* Remade launcher icon, sized correctly.

* I don't know why I can't be satisfied with things.

* Apply suggestions from Scipio

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

* Properly use the settings API instead of Utils.

* Newline on requirements.txt.

* Add __init__ files for frozen builds.

* Replace an ap_inform function with a CommonClient built-in.

* Resize icon to match kivymd expected size.

* First round of Treble code reviews.

* Second round of Treble code reviews.

* Third round of Treble code reviews.

* Missed an unncessary if condition.

* Missed unnecessary comments.

* Fourth round of Treble code reviews.

* Switch trap dictionary to OptionCounter.

* Use existing slot name/seed from network protocol.

* Violet code review updates.

* Violet code review updates part 2.

* Refactor to avoid floating imports (Violet part 3).

* Found a few more valid characters for messaging.

* Move tests out of init, add colon to game name (now that it's safe).

* But don't include those chars for file text.

* Implement Vi suggestion on webhost-capable friendly limits.

* Revert "Implement Vi suggestion on webhost-capable friendly limits."

This reverts commit 2d012b7f4a.

* Rename all files for PEP8.

* Refactor how maximums work on webhost.

* Fix rogue UT.

* Don't rush.

* Fix client post-PEP8.

---------

Co-authored-by: Justus Lind <DeamonHunter@users.noreply.github.com>
Co-authored-by: Romain BERNARD <30secondstodraw@gmail.com>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
2025-05-21 14:12:27 +02:00
NewSoupVi
7f4bf71807 Adventure: Update AdventureDeltaPatch.read_contents to return the manifest as required by #4331 (#5016) 2025-05-21 14:12:00 +02:00
Doug Hoskisson
f3e00b6d62 Zillion: fix read_contents to be compatible with base class (#5015) 2025-05-21 01:48:24 +02:00
Fabian Dill
feef0f484d Core: disable worlds_disabled (#5014) 2025-05-21 00:52:00 +02:00
Fabian Dill
9adbd4031f Core: prepare worlds.Files for APWorldContainer (#4331)
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
2025-05-20 23:55:16 +02:00
Mysteryem
e0d3101066 Core: Remove redundant reachable location counting in swap (#4990)
`prev_state` starts off as a copy of `swap_state` and then `swap_state`
collects `item_to_place`. Collecting an item must never reduce
accessibility (otherwise generation breaks horribly), so it is
guaranteed that `swap_state` will always be able to reach at least as
many locations as `prev_state`, so `new_loc_count >= prev_loc_count` is
always `True`.

As a sideeffect of this change, this fixes generation of Pokemon Emerald
with locally shuffled Badges/HMs when there are worlds with unconnected
entrances present in the multiworld e.g. KH1. This is because this
location counting did not respect `single_player_placement=True` and
counted reachable locations across the entire multiworld.

Fixes #4834 as a sideeffect of removing the redundant code.
2025-05-20 21:23:44 +02:00
SunCat
485387ebbe ChecksFinder: Update setup guide (#4973)
* Update setup_en.md

* Update worlds/checksfinder/docs/setup_en.md

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

* Update worlds/checksfinder/docs/setup_en.md

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

* Update worlds/checksfinder/docs/setup_en.md

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

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-05-20 20:12:13 +02:00
Seldom
9ac628f020 Terraria: remove 1.4.3-specific docs #5013 2025-05-20 20:11:44 +02:00
PoryGone
07664c4d54 SA2B: Logic Fixes (#5009)
- Fixes Shadow's mission count being set by Sonic's mission count option
- Fixes one small logic error on `Security Hall - 5` on Hard Logic difficulty
- Removes stray character that was probably harmless
2025-05-20 00:48:31 +02:00
Aaron Wagener
d3dbdb4491 Kivy: Add a button prompt box (#3470)
* Kivy: Add a button prompt box

* auto format the buttons to display 2 per row to look nicer

* update to kivymd

* have the uri popup use the new API

* have messenger use the new API

* make the buttonprompt import even more lazy

* messenger needs to be lazy too

* make the buttons take up the full dialog width

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-05-19 01:08:39 +02:00
Jérémie Bolduc
90ee9ffe36 Stardew Valley: Remove Crab Pot Requirement for Help Wanted Fishing (#4985)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-05-17 09:20:53 -04:00
el-u
15e6383aad lufia2ac: rearrange tests to comply with new conventions (#5001) 2025-05-15 17:58:10 +00:00
Scipio Wright
2a0d0b4224 Noita: Modernization Refactor (#4980) 2025-05-14 07:55:45 -04:00
Nicholas Saylor
02fd75c018 Core: Update Some Outdated Typing (#4986) 2025-05-14 07:40:38 -04:00
agilbert1412
a87fec0cbd SDV: Add Missing Marriage Requirement for Spouse Stardrop (#4988) 2025-05-14 07:27:15 -04:00
Natalie Weizenbaum
11842d396a DS3: Fix the Name of "Red and White Round Shield" (#4994)
This item name is unusual in that it loses the word "round" when it's
infused, *and* the only guaranteed drop in the base game is the infused
"Blessed Red and White Round Shield +1". But since we're just listing
the uninfused version, we should use the uninfused name.
2025-05-14 07:23:12 -04:00
Ixrec
72854cde44 Docs: Add a "Missable Locations" Question to apworld FAQ (#4965)
* Docs: add a "missable locations" question to apworld_dev_faq.md

Basically turning the conversation at https://discord.com/channels/731205301247803413/1214608557077700720/1368996789260128388 into a FAQ entry.

* feedback

* qwint feedback

* Update docs/apworld_dev_faq.md

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

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-05-14 07:21:40 -04:00
Duck
b71c8005e7 AHiT: Fix Client Argument Handling (#4992) 2025-05-14 07:18:36 -04:00
Ixrec
0994afa25b Tests: actually run tests in __init__.py files (#4969)
* demonstrate our pytest/CI configuration missing a __init__ test failure

* tell pytest/CI to run tests in __init__.py files

* revert the demonstration test failure

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-05-13 09:59:41 +02:00
Jérémie Bolduc
7d5693e0fb Stardew Valley: Move BaseTest out of __init__.py to comply with future conventions (#4991)
* move everything out of init; fix from imports and some typing errors

* why is there a change in multiserver

* fix some relative shits
2025-05-13 09:58:03 +02:00
black-sliver
feaed7ea00 Docs: tests: add naming / file naming conventions (#4982)
* Docs: tests: add naming / file naming conventions

Deprecates putting stuff into `__init__.py`.
This may be relevant for test discovery in the future.

* Docs: tests: fix class naming

* Docs: tests: update examples

* Punctuation is hard

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

* Revert part of one suggestion

The first set of () make the sentence make less sense.

* Docs: tests: clarify that __init__.py may be empty

* Make sentence nicer to read

I simply kept the original wording, but I agree that it reads somewhat odd

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

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: Ixrec <ericrhitchcock@gmail.com>
2025-05-13 09:49:43 +02:00
Justus Lind
8340371f9c Muse Dash: Update to Otaku Pack Vol 20 (#4924)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-05-12 18:47:19 -04:00
Emerassi
824caaffd0 Docs: clarify that ModuleUpdate.py is a prerequisite for running tests (#4970)
* Update tests.md

Spelled out that tests will not run without running UpdateModule.py first and including a link to the instructions on how to do that.

* Applied black-silver's feedback and also I ran into tests that don't run correctly unless you also have run Webhost.py once.  I have included that in the documentation as well.

* More black-silver feedback.
2025-05-11 12:41:35 +02:00
lordlou
c0b3fa9ff7 SMZ3: replace copyright credits music (#4978) 2025-05-11 08:10:51 +02:00
Aaron Wagener
e809b9328b The Messenger: do all empty state validation during portal shuffle (#4971) 2025-05-11 00:57:16 +02:00
qwint
53defd3108 MultiServer: More Guardrails for Nolocation Clients (#4470) 2025-05-10 18:51:44 -04:00
Silvris
a166dc77bc Core: Plando Items "Rewrite" (#3046) 2025-05-10 18:49:49 -04:00
Szabó Benedek Zoltán
68ed208613 DS3: "US: Homeward Bone - foot, drop overlook" (#4875) 2025-05-10 18:31:05 -04:00
agilbert1412
8f71dac417 Stardew valley: Add Trap Distribution setting (#4601)
Co-authored-by: Jouramie <16137441+Jouramie@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-05-10 17:57:24 -04:00
Katelyn Gigante
5f24da7e18 Core: Use the location of Utils.py rather than __main__ to determine the AP Folder (#4009) 2025-05-10 15:20:43 +02:00
NewSoupVi
4e61f1f23c Core: Institute limit of 10000 items on StartInventory (#4972)
* Institute limit on StartInventory

* Update Options.py

* Update Options.py

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

* Update Options.py

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-05-10 04:11:39 +02:00
Fabian Dill
cbfcaeba8b Subnautica: use less multiworld API (#4977) 2025-05-10 00:05:18 +02:00
palex00
9a8abeac28 Add blurb about patch files to the host page (#4974) 2025-05-09 14:27:43 +00:00
digiholic
b0f42466f0 MMBN3: Adds Beach Access to Help With Rehab Job Bonus Reward Check (#4963) 2025-05-08 13:31:00 -04:00
kbranch
bcd7d62d0b LADX: Improve Fake Tracker Items (#4897) 2025-05-07 14:53:58 -04:00
digiholic
703f5a22fd OSRS: New Tasks, New Options, Compatibility with new Plugin Features (#4688) 2025-05-07 13:43:03 -04:00
Benjamin S Wolf
1ee8e339af Launcher: Warn if there is no File Browser (#4275) 2025-05-07 12:51:26 -04:00
Ixrec
dffde64079 Docs: add a "soft logic" question to apworld_dev_faq.md (#4953)
* add a "soft logic" question to apworld_dev_faq.md

* Update apworld_dev_faq.md

* 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>

* add a reminder about progression and how it influences soft logic implementations

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-05-07 12:20:21 -04:00
Scipio Wright
17bc184e28 TUNIC: Add Hidden all_random Option (#4635) 2025-05-07 10:59:16 -04:00
qwint
0ba9ee0695 Docs: update line length in apworld faq doc (#4960) 2025-05-07 10:47:14 -04:00
Scipio Wright
c40214e20f Docs: Minor Changes to apworld_dev_faq.md (#4947)
Co-authored-by: qwint <qwint.42@gmail.com>
2025-05-07 10:41:37 -04:00
Scipio Wright
a3aac3d737 TUNIC: Entrance rando Direction Pairs + Decoupled (#3761)
* Fix merge conflict

* Fix formatting, fix rule for heir access after merge

* Writing combat logic helpers

* More helpers!

* More logic!

* Rename has_stick to has_melee, some fixes per Medic's review

* Clamp max power from sword upgrades

* Wrote the rest of the helpers

* Remove unused import

* Apply item classifications

* Create the combat logic option

* Item classification varies based on option

* Add the shop sword logic stuff in

* Add the rules for the boss-only option

* Fix tiny issues

* Some early Overworld combat logic

* Fill out swamp combat logic

* Add note

* Bump up Boss Scav and Heir

* More revisions to combat logic

* Some changes, currently broken

* New system for power, kinda jank probably

* Revisions to new system, needs more balancing

* Cap attack upgrades

* Uncap mp power since it's directly related to damage output

* Voidlings

* Put together a table showing the vanilla-expected stats for each area

* Added some info on potion counts

* Made new helper functions

* Make has_required_stats

* Make has_combat_reqs

* Update er_rules for new combat reqs

* Fix all the broken things ever

* Remove outdated todo

* Make temp option for testing logic

* More flexible choices for combat items

* Hard require sword for bosses

* Temporarily default combat logic to on

* Finish writing overworld combat logic

* East Forest combat logic done

* Remove a few easy ones

* Finish beneath the well

* Dark Tomb combat logic

* West Garden combat logic

* make unit tests checkmark again

* Weird west garden dagger house edge case

* Try block for that weird west garden edge case

* Add quarry combat logic

* Update to filter out unreachable regions outside of ER

* Fortress Grave Path logic, and a couple fixes to the west garden logic

* Fortress east shortcut logic, and rewriting the try except blocks to use finally

* Refactor to use a new function cause wow there was a lot of repeated code

* Add combat logic to the other two sets of fortress fuses

* Add combat rules to beneath the vault

* Fix missing cathedral -> elevator connection

* Combat logic for cathedral to elevator

* Add cathedral main region, rename cathedral -> cathedral entry

* Setup cathedral combat logic

* Adjust locations' regions for ER

* Add laurels zip logic to the chest in the spike room in cathedral

* Add combat logic to frog's domain

* Move frog's domain locations to regions for combat logic

* Add new frog's domain regions for combat logic

* Update region name for frog's domain

* Fix typo

* Add more regions for lower zig

* Move around lower zig regions for combat logic

* Lower Zig combat logic

* Upper zig combat logic

* Fix typo

* Fix typos

* Fix missing world.

* Update combat logic description

* Add todo

* Add todo

* Don't make zig skip if er or fixed shop is off

* Make it so zig skip is only made with fewer shops and er

* Temporarily default combat logic on

* Update test to explicitly disable combat logic

* Update test_access.py

* Slight wording changes

* Fix bugs, refactor quarry regions so you can access chests in lower quarry with ice grapples

* Run through checks you can do with magic dagger

* Run through checks you can do with magic dagger

* Add rule for entering town portal of having equipment to deal with enemies

* Add rule for atoll near the 6 crabs surrounding a poor defenseless baby slorm

* Update the rule for the chest near the 6 crabs surrounding a slorm to also possibly require laurels

* Revamp combat logic function to work properly without melee

* Add laurels rules to combat logic chests

* Modify beneath the vault bridge rule to need a lantern if combat logic is on

* Put in money logic

* Dagger or combat for swamp big skeleton chest

* Remove the 100 moneys from logic

* Modify lower zig ls drop region destinations

* Remove completed todo

* Reword combat logic option description, remove test option

* Add combat logic to slot data

* Merge Silent's missing slot data bugfix PR #3628

* Remove test combat option

* Update combat logic description

* Fix secret gathering place issue

* Fix secret gathering place issue

* Fix lower zig ls rule

* Fix accidentally removed librarian rule

* Remove redundant rule

* Update gauntlet rule to hard-require a sword

* Add test for a problematic connection

* Adjust combat logic to deal with weird edge cases so it doesn't take stuff out of logic that was previously in logic

* Fix create_item classification

* Update some comments

* Update per exempt's suggestion

* Add combat logic to the well boss fight, reorder the combat logic stuff a little to better section them off

* Add EntranceLayout option

* Add back LogicRules as an invisible option, to not break old yamls

* Fix a bug with seed group, continue changing fixed shop to entrance layout

* Fix missed fixed shop -> entrance layout spot

* Fix bug in seed groups with fixed shop on and off

* Add entrance layout to the UT regen stuff

* Put direction. in, will add them later

* Remove unused elevation from portal class

* Got like half of them in

* Finish adding all of the directions

* Add combat rule for zig front to back

* Update per Medic's suggestion

* Update ladder storage without items option description

* Mess with state with collect and remove to save like 2 seconds (never again)

* Save even more time, still never going to do this again on anything else

* Add option check for collect and remove

* Add directions to shop portals

* Update direction in Portal with default

* Move Direction above Portal

* Add decoupled option, mess with plando connection stuff

* Merge, implement verify plando directions

* Condense the stuff in change and remove to less lines (thanks medic)

* Remove unused thing

* Swap to using logicmixin instead of prog_items (thanks Vi)

* Fix consistency in stat counters

* Add back something that was needed

* Fix mistake when adding back

* Making the fix better (thanks medic)

* Make it actually return false if it gets to the backup lists and fails them

* Fix stuff after merge

* Add outlet regions, create new regions as needed for them

* Put together part of decoupled and direction pairs

* make direction pairs work

* Make decoupled work

* Make fixed shop work again

* Fix a few minor bugs

* Fix a few minor bugs

* Fix plando

* god i love programming

* Reorder portal list

* Update portal sorter for variable shops

* Add missing parameter

* Some cleanup of prints and functions

* Fix typo

* it's aliiiiiive

* Make seed groups not sync decoupled

* Add test with full-shop plando

* Fix bug with vanilla portals

* Handle plando connections and direction pair errors

* Update plando checking for decoupled

* Fix typo

* Fix exception text to be shorter

* Add some more comments

* Add todo note

* Remove unused safety thing

* Remove extra plando connections definition in options

* Make seed groups in decoupled with overlapping but not fully overlapped plando connections interact nicely without messing with what the entrances look like in the spoiler log

* Fix weird edge case that is technically user error

* Add note to fixed shop

* Fix parsing shop names in UT

* Remove debug print

* Actually make UT work

* multiworld. to world.

* Fix typo from merge

* Make it so the shops show up in the entrance hints

* Fix bug in ladder storage rules

* Remove blank line

* # Conflicts:
#	worlds/tunic/__init__.py
#	worlds/tunic/er_data.py
#	worlds/tunic/er_rules.py
#	worlds/tunic/er_scripts.py
#	worlds/tunic/rules.py
#	worlds/tunic/test/test_access.py

* Fix issues after merge

* Update plando connections stuff in docs

* Fix library mistake

* has_stick -> has_melee

* has_stick -> has_melee

* Add a failsafe for direction pairing

* Fix playthrough crash bug

* Remove init from logicmixin

* Updates per code review (thanks hesto)

* has_stick to has_melee in newer update

* has_stick to has_melee in newer update

* # Conflicts:
#	worlds/tunic/__init__.py
#	worlds/tunic/combat_logic.py
#	worlds/tunic/er_data.py
#	worlds/tunic/er_rules.py
#	worlds/tunic/er_scripts.py

* Cleanup more stuff after merge

* Revert "Cleanup more stuff after merge"

This reverts commit a6ee9a93da.

* Revert "# Conflicts:"

This reverts commit c74ccd74a4.

* Cleanup more stuff after merge

* Swap to .get for decoupled so it works with older games probably maybe

* Fix after merge

* Fix typo

* Fix UT support with fixed shop option

* Backport plando connections fix

* Fix issue with fixed shop + decoupled

* Make the error not duplicate the while loop condition

* Fix rule for quarry back to monastery

* Fix more stuff after merge

* Make it not output anything if you set plando connections but not ER

* Add obvious note to plando connections description

* Fix after merge

* add comment to commented out connection

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-05-06 12:33:21 -04:00
Seldom
7bbe62019a Terraria: Fix inaccessible Leading Landlord achievement when getfixedboi is enabled #4958 2025-05-06 18:32:55 +02:00
Aaron Wagener
b898b9d9e6 The Messenger: fix indentation in setup guide (#4959)
* The Messenger: fix indentation in setup guide

* just delete the save backup section tbh
2025-05-06 18:32:30 +02:00
Exempt-Medic
b217372fea Core: Make Perfect Fuzzy Match Prioritize Casing (#4956) 2025-05-05 19:18:20 -04:00
Jérémie Bolduc
b2d2c8e596 Stardew Valley: Add void mayo requirement for Goblin Problem quest (#4933)
This adds the requirement of a void mayo for the Goblin Problem quest. There are also some small adjustments to related rules
- Fishing a void mayo is only considered an option during the Goblin Problem quest, as the odds of finding one after the quest drops drastically.
- Entrance to the witch hut now requires the goblin problem quest, not just a void mayo.
- Fishing rules are all moved to `fishing_logic.py`.
- `can_fish_at` no longer check that you have any of the fishing regions and the region you actually want to fish in.
- created `can_fish_anywhere` and `can_crab_pot_anywhere` to better illustrate when any fish satisfies the rule.
2025-05-04 16:28:38 +02:00
Fabian Dill
68e37b8f9a Factorio: client cleanup and prevent process bomb (#4882)
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-05-04 16:22:48 +02:00
Fabian Dill
fa2d7797f4 Core: update certifi (#4954) 2025-05-04 15:59:41 +02:00
Jonathan Tan
1885dab066 TWW: Documentation Cleanup (#4942) 2025-05-03 20:06:16 -04:00
Tim Mahan
9425f5b772 Docs: Direct Mac users to Launcher.py (#4767) 2025-05-03 08:42:52 -04:00
Fabian Dill
83ed3c8b50 Core: always embed Archipelago (#4880) 2025-05-03 11:53:52 +02:00
qwint
f4690e296d CommonClient: remove Datapackage Version handling (#4487)
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-05-03 01:31:40 +02:00
Fabian Dill
68c350b4c0 CommonClient: rip out old global name lookup (#4941) 2025-05-02 23:39:52 +02:00
Fabian Dill
da0207f5cb Factorio: implement custom filler items (#4945) 2025-05-02 23:39:14 +02:00
Aaron Wagener
2455f1158f Options: Cleanup CommonOptions.as_dict (#4921)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-05-02 12:39:58 -04:00
Fabian Dill
1031fc4923 Factorio: remove FactorioClient executable (#4928) 2025-05-02 15:59:27 +02:00
qwint
6beaacb905 Generate: Better yaml parsing error messaging (#4927)
Co-authored-by: massimilianodelliubaldini <8584296+massimilianodelliubaldini@users.noreply.github.com>
2025-05-02 09:46:34 -04:00
Scipio Wright
c46ee7c420 TUNIC: Lock pre-placed filler to make the game play nicer with prog balancing (#4917) 2025-04-30 21:57:46 +02:00
Bryce Wilson
227f0bce3d Pokemon Red/Blue: Convert to Procedure Patch (#4801) 2025-04-30 16:31:33 +02:00
PoryGone
611e1c2b19 SMW: v2.1 Feature Update (#4652)
### Features:
- Trap Link
  - When you receive a trap, you send a copy of it to every other player with Trap Link enabled
- Ring Link
    - Any coin amounts gained and lost by a linked player will be instantly shared with all other active linked players

Co-authored-by: TheLX5 <luisyuregi@gmail.com>
2025-04-30 16:24:10 +02:00
Mysteryem
5f974b7457 SM: Fix FakeROM instances sharing the same data dictionary (#4912)
FakeROM instances were being created with default arguments, which
included a mutable default argument data dictionary, so all FakeROM
instances would be writing to and reading the same dictionary, resulting
in broken patch data in multiworlds with more than one Super Metroid
world.
2025-04-30 04:57:35 +02:00
threeandthreee
3ef35105c8 LADX: Remove copyrighted assets (#4935) 2025-04-30 04:27:54 +02:00
Alchav
ec768a2e89 ALTTP: Swamp Palace West logic fix (#4936) 2025-04-29 16:53:31 +02:00
black-sliver
b580d3c25a CI: add optional windows release build and build attestation (#4940)
* CI: github attestation for manually started builds

* CI: include appimage zsync in build attestation

* CI: github attestation for Linux release builds

* CI: reorder steps in build.yml

* CI: add windows builds to release.yml

* CI: order jobs in release.yml

* CI: add missing permission to release.yml

* CI: enable windows build in release.yml

* CI: false is skip
2025-04-29 08:32:36 +02:00
Jérémie Bolduc
ce14f190fb Stardew Valley: Replace event creation stardew code with add_event (#4922)
* replace event creation stardew code with add_event

* delete unnecessary default args
2025-04-29 00:12:52 +02:00
Jonathan Tan
4e3da005d4 TWW: Fix generation failure with output file (#4932) 2025-04-27 09:43:24 +02:00
Exempt-Medic
0d9967e8d8 OC2: Account for Multiclass Items in Progression Balancing (#4929) 2025-04-26 13:28:07 -04:00
KonoTyran
2624a0a7ea Remove Slay the Spire (#4673)
* Remove Slay the Spire

* remove slay the spire
2025-04-25 20:54:53 +02:00
Nicholas Brochu
8755d5cbc0 Remove Game: Zork Grand Inquisitor (#4884)
* remove zork grand inquisitor

* add apworld to inno setup installdelete
2025-04-25 01:42:42 +02:00
Jérémie Bolduc
abb6d7fbdb Stardew Valley: Replace all add_rule by set_rule #4909 2025-04-24 23:36:25 +02:00
Star Rauchenberger
fc04192c99 Lingo: Use OptionCounter for trap_weights (#4920) 2025-04-24 23:14:42 +02:00
Fabian Dill
d4110d3b2a LttP: make progression health optional (#4918) 2025-04-24 23:10:58 +02:00
NewSoupVi
05c1751d29 Core: Add "OptionCounter", use it for generic "StartInventory" and Witness "TrapWeights" (#3756)
* CounterOption

* bring back the negative exception for ItemDict

* Backwards compatibility

* ruff on witness

* fix in calls

* move the contains

* comment

* comment

* Add option min and max values for CounterOption

* Use min 0 for TrapWeights

* This is safe now

* ruff

* This fits on one line again now

* OptionCounter

* Update Options.py

* Couple more typing things

* Update Options.py

* Make StartInventory work again, also make LocationCounter theoretically work

* Docs

* more forceful wording

* forced line break

* Fix unit test (that wasn't breaking?)

* Add trapweights to witness option presets to 'prove' that the unit test passes

* Make it so you can order stuff

* Update macros.html
2025-04-24 22:06:41 +02:00
NewSoupVi
6ad042b349 Core: Add Region.add_event (#2965)
* region.add_event function

* Make it return the location bc why not

* Actually item bc that seems more useful

* Update BaseClasses.py

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

* Update BaseClasses.py

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

* add all the requested features from code review

* oop

* roughly sort args in order of importance (imo)

* Fix typing

---------

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
2025-04-24 21:56:52 +02:00
NewSoupVi
e52d8b4dbd The Witness: Remove first-stage requirements of progressive items from the logic files (#4257)
* Remove extraneous symbol requirements

* Some missed Full Dots cases

* Bruh

* merge error

* merge error 2
2025-04-24 21:56:05 +02:00
NewSoupVi
f288e3469c Core: Add a function docstring to roll_settings to hopefully prevent the weights fiasco from being repeated (#3388)
* Add an option docstring to roll_settings to hopefully prevent the weights fiasco from being repeated

* Update Generate.py

* Update Generate.py
2025-04-24 21:55:48 +02:00
Jarno
5bb87c6da5 Tests: Make overlapping test actually print out the overlaps (#4431) 2025-04-24 15:33:30 -04:00
Aaron Wagener
03768a5f90 Tests: Test that a world can generate with item links (#2081)
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>
2025-04-24 15:23:51 -04:00
Scipio Wright
a84366368f Docs: Update comment for create_item (#4919) 2025-04-24 09:38:30 -04:00
Fabian Dill
29e6a10e42 Setup: offer the default-on option to clean /lib folder on update (#4890)
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-04-24 08:50:34 +02:00
Fabian Dill
febd280fba Setup: use sha256 for timestamp server (#4892) 2025-04-23 20:30:15 +02:00
black-sliver
73964b374c MultiServer: import get_settings from the correct module (#4914)
* MultiServer: import get_settings from the correct module

* MultiServer: settings: use attr inbstead of dict access
2025-04-23 15:40:36 +00:00
Jérémie Bolduc
bad6a4b211 Stardew Valley: remove BaseLogic generic so importing mixins is no longer needed (#4916)
* remove BaseLogic generic so importing mixins is no longer needed

* self review
2025-04-23 17:31:08 +02:00
Scipio Wright
57d3c52df9 TUNIC: More varied reserved locations for local_fill option (#4653)
* Make reserved locations more varied

* Use CollectionState(self.multiworld) instead of whatever it used to be
2025-04-21 23:41:20 +02:00
Star Rauchenberger
d309de2557 Lingo: Rework Early Good Items (#4910) 2025-04-21 16:06:24 -04:00
Scipio Wright
d5d56ede8b TUNIC: Remove Outdated Plando Code (#4908) 2025-04-21 15:20:22 -04:00
Fabian Dill
6613c29652 Core: print both world source paths in case of conflict (#4751) 2025-04-21 00:53:40 +02:00
NewSoupVi
1a6de25ab6 Core, all worlds: Hard-deprecate old options API (by August 10th 2024) (#3284)
* Core: deprecate old options API

* also deprecate assigning options via option_definitions

---------

Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
2025-04-21 00:43:31 +02:00
NewSoupVi
b62c1364a9 MultiServer.py: Another Hint Priority + Item Links bug oh boy (#4874)
Basically, hints for itemlink worlds' locations get stored in ctx.hints under
1. the location's player
2. **every individual player** that is participating in the itemlink.

Right now, the updatehint code tries to replace and resend the hint under the itemlinked player, which doesn't work.
2025-04-21 00:43:05 +02:00
Fabian Dill
b59162737d LttP: increase gen rate of pedestal goal with limited rupee pool (#4905)
* LttP: increase gen rate of pedestal goal with limited rupee pool

* improve chance further if retro bow is involved
2025-04-20 23:04:40 +02:00
Jérémie Bolduc
543dcb27d8 Stardew Valley: Exclude maximum one resource packs from pool when in start inventory (#4839)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-04-20 10:51:03 -04:00
Jérémie Bolduc
22941168cd Stardew Valley: Refactor Animals to use Content Packs (#4320) 2025-04-20 10:17:22 -04:00
Scipio Wright
33dc845de8 TUNIC: Fix UT Issue with Fewer Shops Option (#4873) 2025-04-20 09:48:09 -04:00
LiquidCat64
be0f23beb3 CV64: Some DeathLink Adjustments (#4727) 2025-04-20 09:46:57 -04:00
Silvris
b76f2163a4 MM2: Fix invalid weakness failsafe and refactor weakness tests (#4899) 2025-04-20 09:08:30 -04:00
Omnises Nihilis
04aa471526 KH2: Update Docs (#4871) 2025-04-20 08:43:52 -04:00
Trevor L
b756a67c2a BRC: Update Setup Guide (#4861)
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-04-20 08:31:58 -04:00
Jérémie Bolduc
a76ee010eb Stardew Valley: Make Bus and Boat Require Money (#4833) 2025-04-20 08:21:02 -04:00
shananas
eb1fef1f92 KH2: Update Docs (#4869) 2025-04-20 08:20:23 -04:00
Doug Hoskisson
e498cc7d48 Tests: Don't use type as Callable (#4866) 2025-04-20 07:21:40 -04:00
Doug Hoskisson
a26abe079e Zillion: Some Code Cleaning (#4780) 2025-04-20 07:07:17 -04:00
qwint
199b6bdabb Launcher: Update header docstring (#4777) 2025-04-20 07:04:56 -04:00
SunCat
e4bc7bd1cd Checksfinder: Fix the last remnant of outdated game description (#4893)
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-04-20 00:16:46 -04:00
Silvris
20651df307 kvui: fix kwargs on ResizableTextField and ImageButton (#4903) 2025-04-20 01:21:11 +02:00
massimilianodelliubaldini
f857933748 Launcher: Add search box (#4863)
* Add fuzzy search box to Launcher.

* move func bind to the kv and prefer substring matching (#79)

* move the func bind to the kv

* prefer substr matching

* Remove fuzzy results, rely on substring only.

* Use early return instead of else.

* Add type hint to filter_clients_by_type.

* Activate search on keyboard input.

* Clear search box when filtering by type.

* Update Launcher.py

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

---------

Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-04-19 23:27:03 +02:00
Jérémie Bolduc
efe2b7c539 Core: Support default value with cache_self1 (#4667)
* add cache_self1_default and tests

* merge the two decorators

* just change the defaults of the wrap lol

* add test for default and default
2025-04-19 17:55:02 +02:00
Fabian Dill
e090153d93 LttP: fix generation if other games are involved (#4901) 2025-04-19 15:44:55 +02:00
Silvris
5088b02bfe Unittests: fix world unittests with unittest module (#4895) 2025-04-19 15:42:20 +02:00
Nicholas Saylor
57a716b57a LTTP: Update to options API (#4134)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-04-18 23:41:38 +02:00
Aaron Wagener
1b51714f3b LTTP: Rip Lttp specific entrance code out of core and use Region helpers (#1960) 2025-04-18 23:34:34 +02:00
ScootyPuffJr1
cb3d35faf9 LttP: Add keydrop locations to location groups (#4465) 2025-04-18 20:50:51 +02:00
Fabian Dill
a0c83b4854 Core: no longer log ID ranges on generate (#4013)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-04-18 20:49:08 +02:00
Fabian Dill
1b3ee0e94f Core: require clients to support overlapping IDs (#4451) 2025-04-18 20:41:09 +02:00
Mysteryem
552a6e7f1c Stardew Valley: Precollect building items in deterministic order (#4883)
#4239 refactored buildings, but introduced iteration of a set when precollecting the building items into start inventory.

The iteration order of sets varies between separate Python processes due to set order being partially based on the hashes of the objects in the set and because Python processes each have a random hash seed by default.
2025-04-18 18:41:46 +02:00
qwint
38bfb1087b Webhost: fix get_seeds api endpoint (#4889) 2025-04-18 18:15:59 +02:00
qwint
2dc55873f0 Webhost: add link to new session page (#4857)
Co-authored-by: massimilianodelliubaldini <8584296+massimilianodelliubaldini@users.noreply.github.com>
2025-04-18 04:57:41 +02:00
qwint
4b1898bfaf HK: fix docs whitespace (#4885) 2025-04-18 00:57:17 +02:00
Silvris
125bf6f270 Core: Post-KivyMD cleanup 2 and enhancements (#4876)
* Adds a new class allowing TextFields to be resized
* Resizes most CommonClient components to be more in-line with pre-KivyMD
* Change the color of SelectableLabels and TooltipLabels to white
* Fixed ClientTabs not correctly showing the current tab indicator
* The server label now features a (i) icon to indicate that it can be hovered over.
* Changed the default `primary_palette` to `Lightsteelblue` and the default `dynamic_scheme_name` to `VIBRANT`
* Properly set attributes on `KivyJSONToTextParser.TextColors` so that proper typing can be utilized if an individual value is needed
* Fixed some buttons being discolored permanently once pressed
* Sped up the animations of button ripples and tab switching
* Added the ability to insert a new tab to `GameManager.add_client_tab`
* Hovering over the "Command" button in CommonClient will now display the contents of `/help` as a popup (note: this popup can be too large on default height for adequately large /help (SC2 Client), but should always fit fine on fullscreen).
* Fixed invalid sizing of MessageBox errors, and changed their text color to white
2025-04-16 00:09:27 +02:00
Seldom
1873c52aa6 Terraria: 1.4.4 and Calamity support (#3847)
* Terraria integration

* Precollected items for debugging

* Fix item classification

* Golem requires Plantera's Bulb

* Pumpkin Moon requires Dungeon

* Progressive Dungeon

* Reorg, Options.py work

* Items are boss flags

* Removed unused option

* Removed nothing

* Wall, Plantera, and Zenith goals

* Achievements and items

* Fixed The Cavalry and Completely Awesome achievements

* Made "Dead Men Tell No Tales" a grindy achievement

* Some docs, Python 3.8 compat

* docs

* Fix extra item and "Head in the Clouds" being included when achievements are disabled

* Requested changes

* Fix potential thread unsafety, replace Nothing with 50 Silver

* Remove a log

* Corrected heading

* Added incompatible mods list

* In-progress calamity integration

* Terraria events progress

* Rules use events

* Removed an intentional crash I accidentally left in

* Fixed infinite loop

* Moved rules to data file

* Moved item rewards to data file

* Generating from data file

* Fixed broken Mech Boss goal

* Changes Calamity makes to vanilla rules, Calamity final bosses goal

* Added Deerclops, fixed Zenith goal

* Final detailed vanilla pass

* Disable calamity goals

* Typo

* Fixed some reward items not adding to item pool

* In-progress unit test fixes

* Unit test fixes

* `.apworld` compat

* Organized rewards file, made Frog Leg and Fllpper available in vanilla

* Water Walking Boots and Titan Glove rewards

* Add goals to slot data

* Fixed Hammush logic in Post-Mech goal

* Fixed coin rewards

* Updated Terraria docs

* Formatted

* Deathlink in-progress

* Boots of the Hero is grindy

* Fixed zenith goal not placing an item

* Address review

* Gelatin World Tour is grindy

* Difficulty notice

* Switched some achievements' grindiness

* Added "Hey! Listen!" achievement

* Terarria Python 3.8 compat

* Fixed Terraria You and What Army logic

* Calamity minion accessories

* Typo

* Calamity integration

* `deathlink` -> `death_link`

Co-authored-by: Zach Parks <zach@alliware.com>

* Missing `.`

Co-authored-by: Zach Parks <zach@alliware.com>

* Incorrect type annotation

Co-authored-by: Zach Parks <zach@alliware.com>

* `deathlink` -> `death_link` 2

Co-authored-by: Zach Parks <zach@alliware.com>

* Style

Co-authored-by: Zach Parks <zach@alliware.com>

* Markdown style

Co-authored-by: Zach Parks <zach@alliware.com>

* Markdown style 2

Co-authored-by: Zach Parks <zach@alliware.com>

* Address review

* Fix bad merge

* Terraria utility mod recommendations

* Calamity minion armor logic

* ArmorMinions -> Armor Minions, boss rush goal, fixed unplaced item

* Fixed unplaced item

* Started on Terraria 1.4.4

* Crate logic

* getfixedboi, 1.4.4 achievements, shimmer, town slimes, `Rule`, `Condition`, etc

* More clam getfixedboi logic, bar decraft logic, `NotGetfixedboi` -> `Not Getfixedboi`

* Calamity fixes

* Calamity crate ore logic

* Fixed item accessibility not generating in getfixedboi, fixed not generating with incompatible options, fixed grindy function

* Early achievements, separate achievement category options

* Infinity +1 Sword achievement can be location in later goals

* The Frequent Flyer is impossible in Calamity getfixedboi

* Add Enchanted Sword and Starfury for starting inventories

* Don't Dread on Me is redundant in Calamity

* In Calamity getfixedboi, Queen Bee summons enemies who drop Plague Cell Canisters

* Can't use Gelatin Crystal outside Hallow

* You can't get the Terminus without flags

* Typo

* Options difficult warnings

* Robbing the Grave is Hardmode

* Don't reserve an ID for unused Victory item

* Plantera is accessible early in Calamity via Giant Plantera's Bulbs

* Unshuffled Life Crystal and Defender Medal items

* Comment about Midas' Blessing

* Update worlds/terraria/Options.py

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

* Remove stray expression

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

* Review suggestions

* Option naming caps consistency, add Laser Drill, Lunatic Cultist alt reqs, fix Eldritch Soul Artifact, Ceaseless Void reqs Dungeon

* Cal Clone doesn't drop Broken Hero Sword anymore, Laser Drill is weaker in Calamity

Co-authored-by: Seatori <92278897+Seatori@users.noreply.github.com>

* Fix Acid Rain logic

* Fix XB-∞ Hekate failing accessibility checks (by commenting it out bc it doesn't affect logic)

* Hardmode ores being fishable early in Calamity is not a bug anymore

* Mecha Mayhem is inaccessible in getfixedboi

* Update worlds/terraria/Rules.dsv

Co-authored-by: Seafo <92278897+Seatori@users.noreply.github.com>

---------

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
Co-authored-by: Zach Parks <zach@alliware.com>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: Seatori <92278897+Seatori@users.noreply.github.com>
2025-04-15 15:51:05 +02:00
black-sliver
ec1e113b4c Doc: fix parse_yaml in adding games.md (#4872) 2025-04-13 13:10:36 +02:00
agilbert1412
347efac0cd DLC Quest - Skip two long tests in the main pipeline (#4862)
* - Set up the two long tests to only run when the specific config is active

* Apply Black Sliver's suggestion
2025-04-12 02:41:08 +02:00
Jérémie Bolduc
b7b5bf58aa Stardew Valley: Use classvar_matrix to split tests (#4762)
* Unroll tests for better parallelization

* fix ut test

* self review

* bro it's the second time today I have to commit some garbage to have a github action rerun because messenger fails what is this

* my god can the tests plz pass

* code reviews

* code reviews

* move TestRandomWorlds out of long module
2025-04-12 02:19:17 +02:00
Fabian Dill
a324c97815 Factorio: fix FloatRanges writing effectively nil into the mod (#4846) 2025-04-11 20:52:20 +02:00
Natalie Weizenbaum
f263a0bc91 DS3: Mark a lizard location that was previously not annotated (#4860) 2025-04-10 21:18:49 -04:00
Mysteryem
6a9299018c MLSS: Fix generation error with emblem hunt and no digspots (#4859) 2025-04-10 21:17:28 -04:00
Jérémie Bolduc
ee471a48bd Stardew Valley: Fix some determinism issues with entrance rando when playing with mods (#4812) 2025-04-10 14:34:21 -04:00
qwint
879d7c23b7 HK: Workaround for NamedRange webhost bug (#4819) 2025-04-10 14:18:43 -04:00
massimilianodelliubaldini
934b09238e Docs: Update to adding games.md (#4816) 2025-04-10 13:21:33 -04:00
Carter Hesterman
1fd8e4435e Civ 6: Update setup documentation to account for common pitfalls (#4797) 2025-04-10 13:19:03 -04:00
Aaron Wagener
50fd42d0c2 The Messenger: Add a plando guide (#4719) 2025-04-10 13:13:38 -04:00
Aaron Wagener
399958c881 The Messenger: Add an FAQ (#4718) 2025-04-10 13:03:05 -04:00
qwint
78c93d7e39 Docs: Add FAQ section for corrupted metadata debugging (#4705)
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-04-10 13:00:48 -04:00
qwint
e3b8a60584 Webhost: Fix Sphere Tracker crashing on item links (#4855) 2025-04-10 03:29:11 +02:00
Star Rauchenberger
b7263edfd0 Lingo: Removed unnecessary "global" keywords (#4854) 2025-04-10 01:41:07 +02:00
Ziktofel
1ee749b352 SC2 Client: Fix missing mission tooltip after KivyMD switch (#4827) 2025-04-09 22:21:16 +02:00
Alchav
f93734f9e3 Pokemon Red and Blue: PC Item Fix (#4835)
* Pokemon Red and Blue PC Item fix

* Respect non_local_items for PC Item

* prefer exclude if also in priority locations

---------

Co-authored-by: alchav <alchav@jalchavware.com>
2025-04-09 13:20:56 -04:00
Fabian Dill
e211dfa1c2 WebHost: use JS to refresh waitSeed if scripting is enabled (#4843) 2025-04-09 07:43:28 +02:00
Zach 'Phar' Parks
0f7deb1d2a WebHost: Remove styleController.js and replace functionality with HTML/CSS. (#4852)
* ensure footer stays at bottom of page without JS

* Remove some other usages.
2025-04-08 23:46:46 -05:00
black-sliver
f2cb16a5be CI: update action ubuntu build runners to 22.04 (#4847) 2025-04-09 01:38:46 +02:00
Mysteryem
98477e27aa Core: Speed up fill_restrictive item_pool pop loop (#4536)
* Core: Speed up fill_restrictive item_pool pop loop

Items from `reachable_items` are placed in last-in-first-out order, so
items being placed will be towards the end of `item_pool`, but the
iteration to find the item was iterating from the start of `item_pool`.

Now also uses `del` instead of `.pop()` for an additional, tiny,
performance increase.

It is unlikely for there to be a noticeable difference in most cases.
Only generating with many worlds with a high percentage of progression
items and fast access rules is likely to see a difference with this
change.

--skip_output generation of 400 template A Hat in Time yamls with
progression balancing disabled goes from 76s to 43s (43% reduction) for
me with this patch. This placed 43200 progression items out of 89974
items total (48% progression items).

* Fix comment typo

"be" was missing.

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-04-08 23:57:31 +02:00
threeandthreee
4149db1a01 LADX: Stop using Utils.get_options (#4818)
* init

* use get

* Update LinksAwakeningClient.py

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

* Update LinksAwakeningClient.py

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

---------

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
2025-04-08 23:54:50 +02:00
Jérémie Bolduc
9ac921380f Stardew Valley: Refactor buildings to use content packs (#4239)
* create building data object and rename ItemSource to Source to be more generic

# Conflicts:
#	worlds/stardew_valley/content/game_content.py

# Conflicts:
#	worlds/stardew_valley/data/artisan.py
#	worlds/stardew_valley/data/game_item.py
#	worlds/stardew_valley/data/harvest.py
#	worlds/stardew_valley/data/shop.py

* remove compound sources, replace by other requirements which already handle this usecase

* add coops to content packs

* add building progression in game features

* add shippping bin to starting building; remove has_house

* replace config check with feature

* add other buildings in content packs

* not passing

* tests passes, unbelievable

* use newly create methods more

* use new assets to ease readability

* self review

* fix flake8 maybe

* properly split rule for mapping cave systems

* fix tractor garage name

* self review

* add upgrade_from to farm house buldings

* don't override building name variable in logic

* remove has_group from buildings

* mark some items easy in grinding logic so blueprints buildings can be in more early spheres

* move stuff around to maybe avoid future conflicts cuz I have like 10 PRs opened right now

* remove price_multiplier, turns out it's unused during generation

* disable shop source for mapping cave systems

* bunch of code review changes

* add petbowl and farmhouse to autobuilding

* set min easy items to 300

* fix farm type
2025-04-08 12:37:45 -04:00
CookieCat
286e24629f AHIT: Add start_inventory_from_pool and get_filler_item_name (#4798)
* Update __init__.py

* Update Options.py
2025-04-08 12:26:30 -04:00
Emily
ab2efc0c5c kvui: actually fix [u] and [/u] appearing in copied hints (#4842) 2025-04-08 18:06:19 +02:00
NewSoupVi
60d6078e1f Wind Waker: Don't collect nonprogression #4826 2025-04-07 23:17:25 +02:00
black-sliver
f94492b2d3 CI: ignore F824 (#4790)
This is an added check in flake8 that does not really fit the goal
of the github action and currently throws a lot of errors.
2025-04-07 00:39:25 +02:00
Star Rauchenberger
f03bb61747 Lingo: Add "shuffle_postgame" flag to slot data (#4825)
This allows the tracker to see whether postgame is shuffled in the player's world, and if it's not, allows it to hide locations/paintings accordingly.
2025-04-07 00:02:34 +02:00
Silvris
dc4e8bae98 Core: post-KivyMD cleanup (#4815)
* Removed now unused imports from Launcher
* Moved ImageIcon and ImageButton to use ApAsyncImage for compatibility with apworlds
* Adjusted image size in the Launcher from 40x40 to 48x48. This is already larger than the size in previous versions, and a docs update is soon to follow.
* Expose `dynamic_scheme_contrast` to user.kv, allowing users to set high contrast.
* ScrollBox's default scroll_type was set to only content, so the scrollbar in Launcher was nonfunctional.
* Adjusted the spacing of the title of a component when a description is present to be closer to the center.
* Launcher now scrolls to the top automatically when changing between filters
2025-04-06 20:11:16 +02:00
Star Rauchenberger
ac26f8be8b Lingo: Mark some items as ProgUseful (#4822) 2025-04-06 19:44:33 +02:00
black-sliver
8c79499573 SoE: remove use of deprecated Utils.get_options() (#4821) 2025-04-06 17:00:14 +02:00
black-sliver
63fbcc5fc8 WebHost: custom proc title for Generator and MultiHoster (#4310)
* WebHost: custom proctitle for Generator and MultiHoster

* Update setproctitle to 1.3.5
2025-04-06 13:50:24 +02:00
Fabian Dill
cad217af19 Core: update cert file daily in customserver.py (#4454) 2025-04-06 05:31:14 +02:00
Exempt-Medic
a6ad4a8293 Docs: Remove false claim that rules can be done in generate_basic (#4809) 2025-04-05 13:51:22 -04:00
Silvris
503999cb32 Core: KivyMD and Launcher overhaul (#3934)
Shifts the contents of `kvui.py`, and thus all CommonClient-based clients as well as Launcher, to using KivyMD. KivyMD is an extension for Kivy that is almost fully compatible with pre-existing Kivy components, while providing Material Design support for theming and overall visual design as well as useful pre-existing built in components such as Snackbars, Tooltips, and a built-in File Manager (not currently being used).

As a part of this shift, the launcher was completely overhauled, adding the ability to filter the list of components down to each type of component, the ability to define favorite components and filter to them, and add shortcuts for launcher components to the desktop. An optional description field was added to Component for display within the new launcher.

The theme (Light/Dark) and primary palette have also been exposed to users via client/user.kv.
2025-04-05 18:46:24 +02:00
threeandthreee
c2d8f2443e LADX: more tracker support (#4355)
* init

* oops
2025-04-05 18:39:31 +02:00
Ishigh1
4571ed7e2f Core: Made want_reply follow the specs in the docs #4750 2025-04-05 18:35:00 +02:00
Exempt-Medic
ef5cbd3ba3 Adventure: Set Victory Condition Earlier (#4810) 2025-04-05 12:30:08 -04:00
Aaron Wagener
5c162bd7ce Core: add an is_event property to Item to match the one on Location (#3401) 2025-04-05 18:07:06 +02:00
NewSoupVi
7bdaaa25c1 Core: Prevent worlds from using LogicMixin incorrectly (having class variables without an init_mixin) (#3974)
* Core: Prevent people from using LogicMixin incorrectly

There's a world that ran into some issues because it defined its custom LogicMixin variables at the class level.

This caused "instance bleed" when new CollectionState objects were created.

I don't think there is ever a reason to have a non-function class variable on LogicMixin without also having `init_mixin`, so this asserts that this is the case.

Tested:
Doesn't fail any current worlds
Correctly fails the world in question

Also, not gonna call out that world because it was literally my fault for explaining it to them wrong :D

* Verbose af

* Update AutoWorld.py
2025-04-05 18:06:30 +02:00
NewSoupVi
9a5a02b654 MultiServer Extend datastore "update" operation to work on lists as well, acting as a pseudo "set union". #4666 2025-04-05 18:05:58 +02:00
Mysteryem
4fea6b6e9b Core: Remove Location.__hash__ (#4274)
`Location` does not override `__eq__` so should not override `__hash__`.

With this patch, this makes operations on sets of locations slightly
faster because they will use `object.__hash__` rather than
`Location.__hash__`.

`object.__hash__` is about 4 to 5 times faster than `Location.__hash__`
for me. Generation often uses sets of locations, so this slightly speeds
up generation.

The only place I could find that was hashing locations directly was
`WitnessLocationHint.__hash__`, but it has implemented a matching
`__eq__`, so is fine.

For security reasons, Python randomizes its hash seed each time it is
started, so the result of the `hash()` function is nondeterministic and
can't have been used by worlds for anything that needed to be
deterministic and can't have been used to compare information hashed at
generation time to information hashed by a client.
2025-04-05 17:53:59 +02:00
Mysteryem
bd8b8822ac Core: Pass maximum exploration states in distribute_items_restrictive (#4535)
The base state passed to fill_restrictive should be as maximal as
possible otherwise fill_restrictive has to repeatedly re-sweep and
collect from advancement locations that were reachable from before
fill_restrictive has placed a single item.

This is not added within fill_restrictive itself because it is common
for fills to be performed using a partial 'all_state', which is already
a maximum exploration state.

With --skip_output generation of every template yaml, except FF, KH
and Shivers, this prevented repeatedly re-sweeping 576 advancement
locations in every sweep within progression fill, reducing the
generation time from 124s to 113s for me (8.8% reduction, averaged over
5 generations each).
2025-04-05 17:50:19 +02:00
NewSoupVi
0a44c3ec49 The Witness: Move the Easter Egg Hunt option group lower so that the tooltip isn't cut off (#4789) 2025-04-05 17:48:18 +02:00
NewSoupVi
3262984386 The Witness: Option tooltip clarifications (#4807)
* Missing colon

* Clarify Panel Hunt

* Unnecessary line break

* that wasn't meant to be in here
2025-04-05 17:47:16 +02:00
LiquidCat64
180265c8f4 CVCotM: Fix DeathLinks sent by a different instance of the same slot not being received. (#4726)
* Fix same-slot-different-player DeathLinks not being received.

* A few more comments.
2025-04-05 10:27:51 -04:00
PinkSwitch
a9b4d33cd2 Yoshi's Island: Fix Piece of Luigi not goaling until reset (#4709) 2025-04-05 16:07:37 +02:00
Mysteryem
5dfb9b28f7 Core: Improve iteration speed of Region.Register objects (#4583)
Without implementing __iter__ directly, calling iter() on a
Region.Register on Python 3.12 would return a new generator implemented
as follows:
```py
        def __iter__(self) -> int:
            i = 0
            try:
                while True:
                    v = self[i]
                    yield v
                    i += 1
            except IndexError:
                return None
```
This was determined by disassembling the returned generator with
dis.dis() and then constructing a function that disassembles into the
same bytecode.

The iterator returned by `iter(self._list)` is faster than this
generator, so using it slightly improves generation performance on
average.

Iteration of Region.Register objects is used a lot in
`CollectionState.update_reachable_regions` in both of the private
_update methods that get called. The performance gain here will vary
depending on how many regions a world has and how many exits those
regions have on average.

For a game like Blasphemous, with a lot of regions and exits, generation
of 10 template Blasphemous yamls with `--skip_output --seed 1` and
progression balancing disabled went from 19.0s to 16.4s (14.2% reduction
in generation duration).
2025-04-05 15:59:39 +02:00
Benjamin S Wolf
ec75793ac3 Core: Add spoiler-only output mode (#4059)
* Core: Add spoiler-only output mode

* spoiler-only exceptions

* Move new errors to mystery_argparse
2025-04-05 09:50:52 -04:00
CodeGorilla
cd4da36863 GER: Only consider usable exits when calculating dead-ends (#4701)
* Only consider usable exits when calculating whether or not a region is a dead-end

* Update EntranceLookup unit tests

* Add new dead-end test

* Add additional explanation to the new test

* minor formatting tweak

based on review feedback

---------

Co-authored-by: CodeGorilla <3672561+Ars-Ignis@users.noreply.github.com>
2025-04-05 09:21:38 -04:00
Nocallia
1749e22569 Stardew: Fix minor grammar issues in Options (#4800) 2025-04-05 08:20:51 -04:00
axe-y
0cce88cfbc DLC Quest: Fix more items than location with non existing start inventory (#4735)
* DLC Quest Bug Fix
Start inventory item that do not exist in the present world do not make more trap item to appear anymore

* Update worlds/dlcquest/Items.py

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

* DLC Quest Bug Fix
did the recommendation of Mysteryem and made the item not exist in the pool of item created

* DLC Quest Bug Fix
did the recommendation of agilbert1412 and made a check by name instead of item to itemData

* DLC Quest Bug Fix
overcook failed test

* DLC Quest Bug Fix
re-type correctly a type hint

---------

Co-authored-by: Mysteryem <Mysteryem@users.noreply.github.com>
2025-04-05 08:19:54 -04:00
black-sliver
61e83a300b Clients: stop updating datapackage in persistent_storage (#4799)
Still uses things that are in there but stops writing to it.
2025-04-05 11:51:01 +02:00
Exempt-Medic
136a13aac7 Docs: Include that DeathLink cause can be an empty string (#4729) 2025-04-04 22:39:18 -04:00
massimilianodelliubaldini
2c90db9ae7 Docs: Additional detail and organization to adding games.md (#4805)
* Additional detail and organization to adding games.md

* Minor fixes.

* Update docs/adding games.md

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

* Code review updates.

* More updates.

* Client icon blurb.

* Update docs/adding games.md

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

* Revert one line.

* Filler item name blurb.

* Updates for Violet.

* Reorganize client expectations.

* Missed a line delete.

* Doctor's orders

---------

Co-authored-by: qwint <qwint.42@gmail.com>
2025-04-05 04:18:47 +02:00
Richard Snider
507e051a5a Core: Handle integer arguments in player names gracefully (#4151) 2025-04-05 03:36:20 +02:00
Scipio Wright
b5bf9ed1d7 TUNIC: Error message in the spot that UT errors at if you have an old APWorld #4788
Schnice and Shrimple
2025-04-05 00:53:13 +02:00
Fabian Dill
215eb7e473 core: increment version (#4808) 2025-04-04 23:25:37 +02:00
qwint
f42233699a Core: make accessibility_corrections only state.remove if the location was collected 2025-04-04 23:20:45 +02:00
massimilianodelliubaldini
1bec68df4d WebHost: Standardize some 404 redirects (#4642) 2025-04-04 23:11:45 +02:00
CodeGorilla
d8576e72eb Pokemon Red/Blue: Set allow_partial_entrances to true when building a state for ER #4802
Co-authored-by: CodeGorilla <3672561+Ars-Ignis@users.noreply.github.com>
2025-04-04 10:48:47 +02:00
Fabian Dill
7265468e8d kvui: fix [u] and [/u] appearing in copied hints (#4794) 2025-04-03 09:22:02 +02:00
Fabian Dill
d07f36dedd Core: increment version (#4787) 2025-04-02 05:35:39 +02:00
Scipio Wright
364a1b71ec TUNIC: Note Death Link and Trap Link in-game toggles on Game Info page (#4741)
* Note death link and trap link in game info page

* Update worlds/tunic/docs/en_TUNIC.md

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

* Turn it into a bulleted list
2025-04-01 19:55:19 -04:00
Sanjay Govind
daee6d210f CommonClient: don't update ui hints if there is no ui (#4791) 2025-04-02 01:54:27 +02:00
Bryce Wilson
96be0071e6 Pokemon Emerald: Move recent change to new version (#4793) 2025-04-02 00:50:39 +02:00
threeandthreee
ff8e1dfb47 Launcher: Remove an unnecessary global (#4785) 2025-04-01 21:28:59 +02:00
LiquidCat64
d26db6f213 CV64: Fix some unrandomized locations containing unintended items on specific settings (#4728)
* Fix some unrandomized locations on specific settings.

* Remove now-unnecessary comment
2025-04-01 12:37:49 -04:00
Fabian Dill
bb6c753583 FFMQ: fix remote code execution (#4786) 2025-04-01 18:19:07 +02:00
Mysteryem
ca08e4b950 Super Metroid: Replace random module with world random in variaRandomizer (#4429) 2025-04-01 18:14:47 +02:00
Bryce Wilson
5a6b02dbd3 Pokemon Emerald: Fix pre-fill problems (#4686)
Co-authored-by: Mysteryem <Mysteryem@users.noreply.github.com>
2025-04-01 18:12:43 +02:00
jamesbrq
14416b1050 MLSS: Fix issue with door opening earlier than intended (#4737) 2025-04-01 18:10:51 +02:00
Carter Hesterman
da4e6fc532 Civ6: Sanitize player/item values before they go in the XML (#4755) 2025-04-01 18:09:59 +02:00
Justus Lind
57d8b69a6d Muse Dash: Update Song List to Muse Dash Legend. (#4775)
* Add Muse Dash Legend songs.

* Add a new SFX trap
2025-04-01 18:08:09 +02:00
Silvris
c9d8a8661c kvui: Fix hint tab formatting regression (#4778)
Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2025-04-01 18:06:49 +02:00
Fabian Dill
4a3d23e0e6 Core: update cx-Freeze to 8.0.0 & Worlds: fix packages missing __init__.py (#4773) 2025-04-01 16:29:32 +02:00
PoryGone
a3666f2ae5 SA2B: Fix critical typo #4779 2025-03-30 22:19:24 +02:00
Kaito Sinclaire
c3e000e574 id Tech 1 games: Logic updates (Feb '25) (#4677)
- Across Doom 1993 and Doom 2, any items that are accessible in Ultra-Violence from the start of the level without putting the player in any danger are now considered in logic when that level is first received, without needing any weapons available. This is intended to give generation more possible outs for bad placements.
  - This affects the following maps in Doom 1993:
    - Toxin Refinery (E1M3): 1 location.
    - Command Control (E1M4): 1 location.
    - Computer Station (E1M7): 1 location.
    - Deimos Lab (E2M4): 1 location.
    - Tower of Babel (E2M8): 1 location.
    - Unholy Cathedral (E3M5): 1 location.
  - This affects the following maps in Doom 2:
    - The Waste Tunnels (MAP05): 2 locations.
    - Dead Simple (MAP07): 2 locations.
    - The Pit (MAP09): 1 location.
    - Refueling Base (MAP10): 1 location.
    - Nirvana (MAP21): 1 location, except see below.
    - Icon of Sin (MAP30): 9 locations.
    - Grosse (MAP32): 2 locations.
- Doom 2 has had some more significant logical adjustments made.
  - The following Pro tricks have been added to Pro logic:
    - Circle of Death (MAP11): Lowering the exit wall without the Red key by hitting the switch to do so from the nukage. This makes three items previously locked behind the Red key available early, as well as the exit.
    - Suburbs (MAP16): Reaching the exit without any keys, as the gap between the pillar and the wall is large enough to let you through if you position yourself well. While multiple other squeeze glides exist (for example, you can skip the Yellow key in MAP21 by using one), this one is significantly easier than the rest; it does not require much precision, nor does it require vertical mouse movement.
    - Nirvana (MAP21): Skipping the Blue key, as there is a gigantic gap between the bars that attempt to block you.
    - The Chasm (MAP24): Skipping the Blue key by going extremely far through the nukage and finding one of a couple specific teleporters is now considered a Pro trick, and standard logic now expects the key to be obtained.
  - The following levels have had other logic adjustments:
    - The Waste Tunnels (MAP05): Requirements lowered to Shotgun + Super Shotgun + (Chaingun | Plasma gun).
    - The Crusher (MAP06): Requirements lowered to Shotgun + (Chaingun | Plasma gun) for areas immediately accessible. Going beyond the Blue key door also requires Super Shotgun.
    - The Factory (MAP12): The outdoors area, and the little room to the right of where you start, are accessible in sphere 1. These three items are all easily obtainable with only the pistol. The remaining items that are not in the central area are accessible with (Super Shotgun | Plasma gun), while the items in that area are accessible with Super Shotgun + Chaingun + (Plasma gun | BFG9000). This fixes Episode 2 not having an available sphere 1, and allows solo Episode 2 games.
    - Nirvana (MAP21): As above, the item in the starting room is accessible in sphere 1. Every other item that doesn't require a key is accessible with (Super Shotgun | Plasma gun). The room in which you use the Yellow key is accessible with Super Shotgun + Chaingun + (Plasma gun | BFG9000). This fixes Episode 3 not having an available sphere 1, and allows solo Episode 3 games.
    - The Catacombs (MAP22): The four items in the opening room only require (Shotgun | Super Shotgun | Plasma gun). The rest of the level is as before.
    - Bloodfalls (MAP25): Requirements lowered to Shotgun + Super Shotgun + Chaingun, as this level is unusually easy for its placement in the game. Progressing past the Blue key door additionally requires (Rocket launcher | Plasma gun | BFG9000) solely to deal with the Arch-vile at the end of the level.
    - Wolfenstein (MAP31): Requirements lowered to Chaingun + (Shotgun | Super Shotgun). This is closer to what the game expects from a non-secret hunting player from a pistol start.
- The following logic bugs in Heretic have been fixed:
  - Quay (E5M3): An item in a Blue key locked hallway was previously marked as being in the "Main" region, thus considered to be accessible without that key. It has been moved to the appropriate "Blue" region.
  - Courtyard (E5M4): Logic previously assumed you could reach the Wings of Wrath from the opening room, when that isn't actually possible. Changing this moved some items previously in the "Main" region into a new "Green" region, and items previously in the "Kakis" (Yellow OR Green) are now in a "Yellow" region instead. Fixes #4662.
- For known problematic solo episodes, some additional special cases have been added.
  - Doom 1993, Episode 3: One of either the Shotgun or Chaingun is placed early. Slough of Despair (E3M2) is given as an additional starting level.
  - Doom 2, Episode 3: One of either the Super Shotgun or Plasma gun is placed early.
  - Heretic, Episode 1: The Docks (E1M1) - Yellow key is placed early.
- The following levels (and thus, their items and locations) were renamed, due to typos or other oddities:
  - `Barrels o Fun (MAP23)` -> `Barrels o' Fun (MAP23)`
  - `Wolfenstein2 (MAP31)` -> `Wolfenstein (MAP31)`
  - `Grosse2 (MAP32)` -> `Grosse (MAP32)`
  - `D'Sparil'S Keep (E3M8)` -> `D'Sparil's Keep (E3M8)`
  - `The Aquifier (E3M9)` -> `The Aquifer (E3M9)`
2025-03-29 17:32:33 +01:00
Justus Lind
dd5481930a Muse Dash: Update docs to recommend MelonLoader 0.7.0 rather than 0.6.1 (#4776)
* Tiny version update.

* Update wording because there is no longer a latest button
2025-03-29 01:35:35 +01:00
Scipio Wright
842328c661 TUNIC: Update swamp and atoll fuse logic with weaponry (#4760)
* Update swamp and atoll fuse logic with weaponry

* Add it to the swamp and cath rules too
2025-03-28 21:12:16 +01:00
PoryGone
8f75384e2e SA2B - v2.4 Logic Fixes (#4770)
* Logic tweaks

* Docs updates

* Delete extra file

* One more logic tweak

* Add missing logic change
2025-03-28 21:11:31 +01:00
Fabian Dill
193faa00ce Factorio: fix energylink type back to int (#4768) 2025-03-28 00:28:10 +01:00
Star Rauchenberger
5e5383b399 Lingo: Add painting display names (#4707)
* Lingo: Add painting display names

* Reordered some paintings

* Update generated.dat
2025-03-27 01:32:39 +01:00
threeandthreee
cb6b29dbe3 LADX: fix for unconnected entrances in other worlds #4771 2025-03-25 22:30:25 +01:00
Fabian Dill
82b0819051 Core: ensure requirements files end on newline (#4761) 2025-03-24 22:26:30 +01:00
Jérémie Bolduc
e12ab4afa4 Stardew Valley: Move test option presets to their own file (#4349) 2025-03-24 03:32:34 +01:00
Justus Lind
1416f631cc Core: Add a test that checks all registered patches matches the name of a registered world (#4633)
Co-authored-by: qwint <qwint.42@gmail.com>
2025-03-24 03:30:44 +01:00
Fabian Dill
dbaac47d1e Core: update various requirements (#4731) 2025-03-23 17:24:50 +01:00
Jonathan Tan
cf0ae5e31b The Wind Waker: Implement New Game (#4458)
Adds The Legend of Zelda: The Wind Waker as a supported game in Archipelago. The game uses [LagoLunatic's randomizer](https://github.com/LagoLunatic/wwrando) as its base (regarding logic, options, etc.) and builds from there.
2025-03-23 00:42:17 +01:00
BadMagic100
8891f07362 Core: Allow and require user-provided target name when splitting 1-way entrances for GER (#4746)
* [Core][GER] Allow and require user-provided target name when splitting 1-way entrances

* Move target naming onto a parameter of disconnect_entrance_for_randomization
2025-03-22 20:58:35 +01:00
NewSoupVi
d78974ec59 The Witness: Bump Required Client Version to 0.6.0 (#4763)
The beta client releases already report this.
2025-03-22 20:57:22 +01:00
NewSoupVi
32be26c4d7 The Witness: Make sure the 2025 April Fools feature does not go live with RC3 (#4758) 2025-03-22 20:52:18 +01:00
Jérémie Bolduc
9de49aa419 Stardew Valley: Move all the goal logic into its own file (#4383) 2025-03-22 20:29:16 +01:00
PoryGone
294a67a4b4 SA2B: v2.4 - Minigame Madness (#4663)
Changelog:

Features:
- New Goal
  - Minigame Madness
    - Win a certain number of each type of Minigame Trap, then defeat the Finalhazard to win!
	- How many of each Minigame are required can be set by an Option
	- When the required amount of a Minigame has been received, that Minigame can be replayed in the Chao World Lobby
- New optional Location Checks
  - Bigsanity
    - Go fishing with Big in each stage for a Location Check
  - Itemboxsanity
    - Either Extra Life Boxes or All Item Boxes
- New Items
  - New Traps
    - Literature Trap
	- Controller Drift Trap
	- Poison Trap
	- Bee Trap
  - New Minigame Traps
    - Breakout Trap
	- Fishing Trap
	- Trivia Trap
	- Pokemon Trivia Trap
	- Pokemon Count Trap
	- Number Sequence Trap
	- Light Up Path Trap
	- Pinball Trap
	- Math Quiz Trap
	- Snake Trap
	- Input Sequence Trap
- Trap Link
  - When you receive a trap, you send a copy of it to every other player with Trap Link enabled
- Boss Gate Plando
- Expert Logic Difficulty
	- Use at your own risk. This difficulty requires complete mastery of SA2.
- Missions can now be enabled and disabled per-character, instead of just per-style
- Minigame Difficulty can now be set to "Chaos", which selects a new difficulty randomly per-trap received

Quality of Life:
- Gate Stages and Mission Orders are now displayed in the spoiler log
- Additional play stats are saved and displayed with the randomizer credits
- Stage Locations progress UI now displays in multiple pages when Itemboxsanity is enabled
- Current stage mission order and progress are now shown when paused in-level
- Chaos Emeralds are now shown when paused in-level
- Location Name Groups were created
- Moved SA2B to the new Options system
- Option Presets were created
- Error Messages are more obvious

Bug Fixes:
- Added missing `Dry Lagoon - 12 Animals` location
- Flying Dog boss should no longer crash when you have done at least 3 Intermediate Kart Races
- Invincibility can no longer be received in the King Boom Boo fight, preventing a crash
- Chaos Emeralds should no longer disproportionately end up in Cannon's Core or the final Level Gate
- Going into submenus from the pause menu should no longer reset traps
- `Sonic - Magic Gloves` are now plural
- Junk items will no longer cause a crash when in a falling state
- Chao Garden:
	- Prevent races from occasionally becoming uncompletable when using the "Prize Only" option
	- Properly allow Hero Chao to participate in Dark Races
	- Don't allow the Chao Garden to send locations when connected to an invalid server
	- Prevent the Chao Garden from resetting your life count
	- Fix Chao World Entrance Shuffle causing inaccessible Neutral Garden
	- Fix pressing the 'B' button to take you to the proper location in Chao World Entrance Shuffle
	- Prevent Chao Karate progress icon overflow
	- Prevent changing Chao Timescale while paused or while a Minigame is active
- Logic Fixes:
	- `Mission Street - Chao Key 1` (Hard Logic) now requires no upgrades
	- `Mission Street - Chao Key 2` (Hard Logic) now requires no upgrades
	- `Crazy Gadget - Hidden 1` (Standard Logic) now requires `Sonic - Bounce Bracelet` instead of `Sonic - Light Shoes`
	- `Lost Colony - Hidden 1` (Standard Logic) now requires `Eggman - Jet Engine`
	- `Mad Space - Gold Beetle` (Standard Logic) now only requires `Rouge - Iron Boots`
	- `Cosmic Wall - Gold Beetle` (Standard and Hard Logic) now only requires `Eggman - Jet Engine`
2025-03-22 13:00:07 +01:00
panicbit
0e99888926 LADX: Stop spamming location checks over network (#4757) 2025-03-21 17:10:17 +01:00
qwint
74cbf10930 Civ6: Use AutoPatchRegister to make patch downloadable on webhost #4752 2025-03-20 19:28:16 +01:00
BadMagic100
08d2909b0e Hollow Knight: Include Lumafly links to install mods in docs (#4745) 2025-03-20 11:49:55 -04:00
CaitSith2
0949b11436 ALttP: Don't crash generation if sprite paths don't exist (#4725) 2025-03-20 14:48:30 +01:00
Aaron Wagener
9cdffe7f63 The Messenger: Add display names to the plando options (#4748) 2025-03-19 15:52:14 -04:00
Bryce Wilson
8b2a883669 Pokemon Emerald: Update changelog (#4747) 2025-03-19 02:17:01 +01:00
NewSoupVi
b7fc96100c Revert "Core: update websockets (#4732)" (#4753)
This reverts commit 42eaeb92f0.
2025-03-19 01:39:18 +01:00
Aaron Wagener
63cbc00a40 The Messenger: Fix corrupted future rule (#4749) 2025-03-18 19:01:31 -04:00
CodeGorilla
57b94dba6f Options: Add a column for player ID to --csv_output (#4715) 2025-03-17 21:43:00 +01:00
ironminer888
0dd188e108 LADX: Add more specific "item icon guessing" support for some games (#4706)
* DKC3, PKMN R/B/Em, M&L specific item matches

* MLSS Bean types are now discrete

* Add Doom 1/2 items

* Add Doom 1/2 items, actually

* Add Inscryption items

* Add more SA2B items, Minecraft

* Add VVVVVV

* Add misc items, comma fixes

* Hat in Time items

* Misc changes

* Expand TODO

* Add more OoT items, Pokemon consumables

* KH2

* KH1, adjust KH2 items

* Formatting fixes

* more item changes, fix kh1 name

* Fix KH1 name

* Add Full Heal to MEDICINE graphics

* Final comma fixes before PR

* Add Full Restore as Medicine

* Move some names to generic, drink fixes, double-quotes consistency fix

* moved ROCK SMASH match to PHRASES dict

* Removed some redundant name checks, remove Old Amber check from Emerald

* Added "PASS" generic check as "LETTER" sprite

* Removed TODO

* Corrected KH1 name for real this time

* Icon assignment now uppers freogin item string during comparison

* Doom skull keys are now NIGHTMARE_KEY, added QUILL as generic for FEATHER

* KH2 armor is Blunic, accessories are Ribbons

* KH1 accessories/armor are Blunic

* "ROCK SMASH" is now "BOMB"

* Removed extra space
2025-03-17 11:50:57 -04:00
PoryGone
bf8c840293 Celeste 64: v1.3 Content Update (#4581)
### Features:

- New optional Location Checks
	- Checkpointsanity
- Hair Color
	- Allows for setting of Maddy's hair color in each of No Dash, One Dash, Two Dash, and Feather states
- Other Player Ghosts
	- A game config option allows you to see ghosts of other Celeste 64 players in the multiworld

### Quality of Life:

- Checkpoint Warping
	- Received Checkpoint items allow for warping to their respective checkpoint
		- These items are on their respective checkpoint location if Checkpointsanity is disabled
	- Logic accounts for being able to warp to otherwise inaccessible areas
	- Checkpoints are a possible option for a starting item on Standard Logic + Move Shuffle + Checkpointsanity
- New Options toggle to enable/disable background input

### Bug Fixes:

- Traffic Blocks now correctly appear disabled within Cassettes
2025-03-17 02:46:34 +01:00
black-sliver
c0244f3018 Tests: unroll 2 player gen, add parametrization helper, add docs (#4648)
* Tests: unroll test_multiworlds.TestTwoPlayerMulti

Also adds a helper function that other tests can use to unroll tests.

* Docs: add more details to docs/tests.md

* Explain parametrization, subtests and link to the new helper
* Mention some performance details and work-arounds
* Mention multithreading / pytest-xdist

* Tests: make param.classvar_matrix accept sets

* CI: add test/param.py to type checking

* Tests: add missing typing to test/param.py

* Tests: fix typo in test/param.py doc comment

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

* update docs

* Docs: reword note on performance

---------

Co-authored-by: qwint <qwint.42@gmail.com>
2025-03-17 00:16:02 +01:00
black-sliver
8af8502202 CI: pin some actions (#4744) 2025-03-17 00:02:00 +01:00
Fabian Dill
42eaeb92f0 Core: update websockets (#4732) 2025-03-16 22:13:12 +01:00
Alchav
7f35eb8867 Pokémon R/B: Allow generating with all items linked (#4330)
* Pokémon R/B: Allow generating with all items linked

* check priority/excluded locations for pc_item

* Update regions.py

* Un-remove regions.py code
2025-03-16 12:33:24 -04:00
BadMagic100
785569c40c Core: Generic ER fails in stage 1 when the last available target is an indirect conditioned dead end (#4679)
* Add test that stage1 ER will not fail due to speculative sweeping an indirect conditioned dead end

* Skip speculative sweep if it's the last entrance placement

* Better implementation of needs_speculative_sweep

* pep8
2025-03-15 18:56:07 +01:00
Scipio Wright
a9eb70a881 OoT: Remove Outdated Spanish Setup Guide (#4736)
* Remove spanish setup guide from webworld

* Update __init__.py

* Update __init__.py
2025-03-15 07:16:06 -04:00
Scipio Wright
5d3d0c8625 WebHost: Update text for options you can't modify (#4614) 2025-03-15 07:10:07 -04:00
Scipio Wright
7e32feeea3 Webhost: Update random option wording on webhost (#4555)
* Update random option wording on webhost

* Update WebHostLib/templates/playerOptions/macros.html

Co-authored-by: Jouramie <16137441+Jouramie@users.noreply.github.com>
2025-03-15 07:09:04 -04:00
neocerber
0d1935e757 SC2: Add a description of mission order and the impact of collect on a SC2 world (#4398)
* Added mission order to randomized stuff, added a mention to the default option collect on goal, added an issue about mission order progress vs AP collect

* Remove false menion of collect being note modifyable after the mworld was gen

* Simplification of some sentences

* American spelling, header newline, and other

* Revert gray to grey, corrected some colors

* Forgot a gray -> grey

* Replace how the faction color option is described to side-step difference within yaml and client. Both fr/en.
2025-03-14 11:35:58 -04:00
Benny D
9b3ee018e9 Core/Various Worlds: Fix crash/freeze with unicode characters (#4671)
replace colorama.init with just_fix_windows_console
2025-03-14 08:24:37 +01:00
NewSoupVi
1de411ec89 The Witness: Change Regions, Areas and Connections from Dict[str, Any] to dataclasses&NamedTuples (#4415)
* Change Regions, Areas and Connections to dataclasses/NamedTuples

* Move to new file

* we do a little renaming

* Purge the 'lambda' naming in favor of 'rule' or 'WitnessRule'

* missed one

* unnecessary change

* omega oops

* NOOOOOOOO

* Merge error

* mypy thing
2025-03-13 23:59:09 +01:00
LiquidCat64
3192799bbf CVCotM: Clarify the Wii U VC version is unsupported (#4734)
* Comment out VC ROM hash usages and clarify that it's unsupported.

* Update worlds/cvcotm/docs/en_Castlevania - Circle of the Moon.md

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

* Update worlds/cvcotm/docs/setup_en.md

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

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-03-13 00:21:09 +01:00
Aaron Wagener
2c8dded52f The Messenger: Fix some transition plando issues (#4720)
* don't allow one-way and two-way entrances to be connected to each other

* add special handling for the tower hq nodes since they share the same parent region
2025-03-10 22:13:49 -04:00
justinspatz
06111ac6cf OOT: Have beehives that only appear as a child not be in logic if only adult can break beehives (#4646)
* Change the logic for the 3 Zora's Domain Beehives to support new rule

Implement new logic changes to these 3 locations

* Update LogicHelpers.json with new rule for beehives that only appear for child link

Added below the "can_break_upper_beehive" a new helper called "can_break_upper_beehive_child" which removes the requirement for hookshot to avoid a logic error in the Zora Domain Beehives where it checks whether child or adult can break beehives, even though these beehives do not appear as an adult.

* Update LogicHelpers.json moving the call for is_child

As is_child is already called for can_use (Boomerang), it's a bit redundant to include the check for using the Boomerang, so it's being moved to be with the Bombchu check to ensure that it's not expected if the Bombchu Logic Rule is turned on that Adult can use bombchus to break the beehives. This effectively does the same thing, but should be better on performance.
2025-03-10 17:39:45 +01:00
agilbert1412
d83294efa7 Stardew valley: Fix Aurora Vineyard Tablet logic (#4512)
* - Add requirement on Aurora Vineyard tablet to start the quest

* - Add rule for using the aurora vineyard staircase

* - Added a test for the tablet

* - Add a few missing items to the test

* - Introduce a new item to split the quest from the door and avoir ER issues

* - Optimize imports

* - Forgot to generate the item

* fix Aurora mess

# Conflicts:
#	worlds/stardew_valley/rules.py
#	worlds/stardew_valley/test/mods/TestMods.py

* fix a couple errors in the cherry picked commit, added a method to improve readability and reduce chance of human error on story quest conditions

* - remove blank line

* - Code review comments

* - fixed weird assert name

* - fixed accidentally surviving line

* - Fixed imports

---------

Co-authored-by: Jouramie <16137441+Jouramie@users.noreply.github.com>
2025-03-10 11:39:35 -04:00
Dinopony
be550ff6fb Landstalker: Several small fixes (#4675)
* Landstalker: Fixed duplicate entrance names when using the "No teleport tree requirements" option

* Landstalker: Fixed more cases of duplicate entrance names when using "Shuffle Trees" with open trees

* Landstalker: Fixed endgame locations being present in "Reach Kazalt" goal

* Landstalker: Fixed Lithograph hint pointing at the wrong player

* Landstalker: Updated docs to remove the link to Steam since game got delisted

* Landstalker: Fixed high value hint_count rarely failing at generation

* Landstalker: Fixed dynamic shop prices being potentially invalid in case of a progression balancing (changes by ExemptMedic)
2025-03-10 11:35:58 -04:00
Patrick Lübcke
dd55409209 Pokémon R/B: Fix Rock Tunnel B1F randomization (#4670)
* Bottom to central path sealed off

* Bottom-to-left-path to right path sealed off

* Central opening (r4444): Left unsealed, paths seperated

* Top right half rocks fixed

* Middle to top opening sealed

* Right hallway seal correctly positioned

* Top right ladder: Fixed overlapping walls
2025-03-10 11:35:40 -04:00
Mysteryem
e267714d44 AHiT: Rework Subcon Forest Boss Arena, Boss Firewall and YCHE logic (#4494)
A new `Subcon Forest - Behind Boss Firewall` region is added for
`Subcon Village - Snatcher Statue Chest`. `Subcon Forest Area` connects
to this new region, requiring either the first
`Progressive Painting Unlock`, or Expert logic +
`NoPaintingSkips: false`.

A new `Subcon Forest Boss Arena` region is added for
`Subcon Forest - Boss Arena Chest` because this is immediately
accessible from YCHE. There are connections to this region from
`Your Contract has Expired` (no requirements) and from
`Subcon Forest - Behind Boss Firewall` (requiring either Hard logic or
`Hookshot Badge` + `TOD Access`).

A reverse connection is also added to Expert logic, for
`Subcon Forest Boss Arena` -> `Subcon Forest - Behind Boss Firewall`.
This could be extended to include Hard logic if there is a reasonable
Cherry Bridge setup.

A reverse connection is also added to Expert logic, for
`Subcon Forest - Behind Boss Firewall` -> `Subcon Forest Area`, so long
as `NoPaintingSkips: false` because it is impossible to burn the
paintings to remove the firewall, from behind the firewall.

A new `Your Contract has Expired - Post Fight` region is added for the
Snatcher post fight cutscene to prevent the Snatcher Hover trick giving
access to YCHE, which would otherwise also give access to the new
`Subcon Forest Boss Arena` Region.

The paintings and boss arena gap logic for `Snatcher Statue Chest` and
`Boss Arena Chest` are now handled using the connections to/from these
new regions rather than being on the locations themselves.

The logic for `Act Completion (Toilet of Doom)` remains unchanged
because it has to be in the `Toilet of Doom` region.

In Expert logic, with `NoPaintingSkips: false`, YCHE is added as a rift
access region to Subcon Forest Time Rift entrances.

The `YCHE Access` event is no longer used and has been removed.

- Fixes painting skips logic for Subcon Village - Snatcher Statue Chest
- Fixes Subcon Forest - Boss Arena Chest being inaccessible from YCHE
- Adds Expert logic to reach `Snatcher Statue Chest` from YCHE
- Adds Expert logic to skip the boss firewall in reverse from YCHE so
long as painting skips are not removed from logic
- Adds Expert logic to access Subcon Forest Time Rift entrances from
YCHE so long as painting skips are not removed from logic
2025-03-10 11:34:10 -04:00
Aaron Wagener
7c30c4a169 The Messenger: Transition Shuffle (#4402)
* The Messenger: transition rando

* remove unused import

* always link both directions for plando when using coupled transitions

* er_type was renamed to randomization_type

* use frozenset for things that shouldn't change

* review suggestions

* do portal and transition shuffle in `connect_entrances`

* remove some unnecessary connections that were causing entrance caching collisions

* add test for strictest possible ER settings

* use unittest.skip on the skipped test, so we don't waste time doing setUp and tearDown

* use the world helpers

* make the plando connection description more verbose

* always add searing crags portal if portal shuffle is disabled

* guarantee an arbitrary number of locations with first connection

* make the constraints more lenient for a bit more variety
2025-03-10 11:16:09 -04:00
Alchav
4882366ffc LTTP: Fix TR Big Key Door Entrance Logic (#4712) 2025-03-10 15:56:05 +01:00
Carter Hesterman
5f73c245fc New Game Implementation: Civilization VI (#3736)
* Init

* remove submodule

* Init

* Update docs

* Fix tests

* Update to use apcivvi

* Update Readme and codeowners

* Minor changes

* Remove .value from options (except starting hint)

* Minor updates

* remove unnecessary property

* Cleanup Rules and Region

* Fix output file generation

* Implement feedback

* Remove 'AP' tag and fix issue with format strings and using same quotes

* Update worlds/civ_6/__init__.py

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

* Minor docs changes

* minor updates

* Small rework of create items

* Minor updates

* Remove unused variable

* Move client to Launcher Components with rest of similar clients

* Revert "Move client to Launcher Components with rest of similar clients"

This reverts commit f9fd5df9fd.

* modify component

* Fix generation issues

* Fix tests

* Minor change

* Add improvement and test case

* Minor options changes

* .

* Preliminary Review

* Fix failing test due to slot data serialization

* Format json

* Remove exclude missable boosts

* Update options (update goody hut text, make research multiplier a range)

* Update docs punctuation and slot data init

* Move priority/excluded locations into options

* Implement docs PR feedback

* PR Feedback for options

* PR feedback misc

* Update location classification and fix client type

* Fix typings

* Update research cost multiplier

* Remove unnecessary location priority code

* Remove extrenous use of items()

* WIP PR Feedback

* WIP PR Feedback

* Add victory event

* Add option set for death link effect

* PR improvements

* Update post fill hint to support items with multiple classifications

* remove unnecessary len

* Move location exclusion logic

* Update test to use set instead of accidental dict

* Update docs around progressive eras and boost locations

* Update docs for options to be more readable

* Fix issue with filler items and prehints

* Update filler_data to be static

* Update links in docs

* Minor updates and PR feedback

* Update boosts data

* Update era required items

* Update existing techs

* Update existing techs

* move boost data class

* Update reward data

* Update prereq data

* Update new items and progressive districts

* Remove unused code

* Make filler item name func more efficient

* Update death link text

* Move Civ6 to the end of readme

* Fix bug with hidden locations and location.name

* Partial PR Feedback Implementation

* Format changes

* Minor review feedback

* Modify access rules to use list created in generate_early

* Modify boost rules to precalculate requirements

* Remove option checks from access rules

* Fix issue with pre initialized dicts

* Add inno setup for civ6 client

* Update inno_setup.iss

---------

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: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2025-03-10 14:53:26 +01:00
NewSoupVi
21ffc0fc54 Band-aid Linux Build breaking with the release of PyGObject 3.52.1 (#4716)
* Band-aid Linux Build breaking with the release of PyGObject 3.52.1

* Update build.yml

* Release workflow as well
2025-03-10 14:43:52 +01:00
Scipio Wright
e95a41cf93 TUNIC: Add another alias for ladders #4714 2025-03-10 14:24:37 +01:00
Silvris
04771fa4f0 Core: fix pickling plando texts (#4711) 2025-03-09 20:00:00 +01:00
jamesbrq
2639796255 MLSS: Add new goal + Update basepatch to standalone equivalent (#4409)
* Item groups + small changes

* Add alternate goal

* New Locations and Logic Updates + Basepatch

* Update basepatch.bsdiff

* Update Basepatch

* Update basepatch.bsdiff

* Update bowsers castle logic with emblem hunt

* Update Archipelago Unittests.run.xml

* Update Archipelago Unittests.run.xml

* Fix for overlapping ROM addresses

* Update Rom.py

* Update __init__.py

* Update basepatch.bsdiff

* Update Rom.py

* Update client with new helper function

* Update basepatch.bsdiff

* Update worlds/mlss/__init__.py

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

* Update worlds/mlss/__init__.py

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

* Review Refactor

* Review Refactor

---------

Co-authored-by: qwint <qwint.42@gmail.com>
2025-03-09 11:37:15 -04:00
Jérémie Bolduc
4ebabc1208 Stardew Valley: Move filler pool generation out of the world class (#4372)
* merge group options so specific handling is not needed when generating filler pool

* fix

* remove unneeded imports

* self review

* remove unneeded imports

* looks like typing was missing woopsi
2025-03-08 12:13:33 -05:00
josephwhite
ce34b60712 Super Mario 64: ItemData class and tables (#4321)
* sm64ex: use item data class

* rearrange imports

* Dict to dict

* remove optional typing

* bonus item descriptions since we can also add stuff for webworld easily

* remove item descriptions (rip) and decrease verbosity for classifications

* formatting
2025-03-08 12:07:50 -05:00
Trevor L
54094c6331 Blasphemous: Restrict right half of map start locations to hard difficulty only (#4002)
* Start locations, location name

* Fix tests
2025-03-08 11:59:35 -05:00
Bryce Wilson
3986f6f11a Pokemon Emerald: Randomize rock smash encounters (#3912)
* Pokemon Emerald: WIP add rock smash encounter randomization

* Pokemon Emerald: Refactor encounter data on maps

* Pokemon Emerald: Remove unused import

* Pokemon Emerald: Swap StrEnum for regular Enum and use .value
2025-03-08 11:57:16 -05:00
sgrunt
5662da6f7d Timespinner: Support new flags and settings from the randomizer (#4559)
* Timespinner: Add "no hell spiders" enemy rando option that is present in upstream settings

* Timespinner: Prism Break support tweaks (including tracker support)

* Timespinner: Add support for upstream Lock Key Amadeus flag

* Timespinner: Add support for upstream Risky Warps flag

* Timespinner: Add support for upstream Pyramid Start flag

* Timespinner: fix error in lab connectivity logic

* Timespinner: use has_all to simplify one check

Per PR suggestion.

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

* Timespinner: fix apparent logic error inherited from in-rando logic

* Timespinner: adjust "Origins" location logic slightly further to account for a Risky Warps case

* Timespinner: remove the backward compat options for the recent flag additions

* Timespinner: add newly added Gate Keep option from rando

* Timespinner: adjust the laser access colours in the tracker

* Timespinner: fix an item description in the tracker

* Timespinner: based on testing feedback, put Laser Access items in their own category

* Timespinner: add support for new upstream flag Royal Roadblock

* Timespinner: also ensure the new flag gets put in slot data

* Timespinner: fix bug in universal tracker support indicating castle basement is accessible at the lower Rising Tides flooding level

* Timespinner: exclude Talaria Attachment and Timespinner Wheel from pyramid start starter progression items

* Timespinner: fix region logic for the left pyramid warp

* Timespinner: fix main Gyre access logic when Risky Warps warps you behind the lasers

* Timespinner: apply suggested spacing fix

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

---------

Co-authored-by: sgrunt <sgrunt1987@gmail.com>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-03-08 11:54:23 -05:00
Scipio Wright
33a75fb2cb TUNIC: Breakable Shuffle (#4489)
* Starting out

* Rules for breakable regions

* make the rest of it work, it's pr ready, boom

* Make it work in not pot shuffle

* Fix after merge

* Fix item id overlap

* Move breakable, grass, and local fill options in yaml

* Fix groups getting overwritten

* Rename, add new breakables

* Rename more stuff

* Time to rename them again

* Make it actually default for breakable shuffle

* Burn the signs down

* Fix west courtyard pot regions

* Fix fortress courtyard and beneath the fortress loc groups again

* More missing loc group conversions

* Replace instances of world.player with player, same for multiworld

* Update worlds/tunic/__init__.py

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

* Remove unused import
2025-03-08 11:25:47 -05:00
Jérémie Bolduc
ee9bcb84b7 Stardew Valley: Move progressive tool options handling in features (#4374)
* create tool progression feature and unwrap option

* replace option usage with calling feature

* add comment explaining why some logic is a weird place

* replace item creation logic with feature

* self review and add unit tests

* rename test cuz I named them too long

* add a test for the trash can useful stuff cuz I thought there was a bug but turns out it works

* self review again

* remove price_multiplier, turns out it's unused during generation

* damn it 3.11 why are you like this

* use blacksmith region when checking vanilla tools

* fix rule

* move can mine using in tool logic

* remove changes to performance test

* properly set the option I guess

* properly set options 2

* that's what happen when you code too late
2025-03-08 11:19:29 -05:00
Kaito Sinclaire
b5269e9aa4 id Tech Games: Customizable ammo capacity (#3565)
* Doom, Doom 2, Heretic: customizable ammo capacity

* Do not progression balance capacity up items

* Prog fill still doesn't agree, just go with our original idea

* Clean up the new options a bit

- Gave all options a consistent and easily readable naming scheme
  (`max_ammo_<type>` and `added_ammo_<type>`)
- Don't show the new options in the spoiler log,
  as they do not affect logic
- Fix the Doom games' Split Backpack option accidentally referring to
  Heretic's Bag of Holding

The logging change across all three games is incidental, as at some
point I did run into that condition by happenstance and it turns out
that it throws an exception due to bad formatting if it's reached

* Do the visibility change for Heretic as well

* Update required client version

* Remove spoiler log restriction on options

* Remove Visibility import now made redundant
2025-03-08 10:37:54 -05:00
Bryce Wilson
00a6ac3a52 BizHawkClient: Store seed name sent by the server for clients to check (#4702) 2025-03-08 16:14:25 +01:00
Bryce Wilson
ea8a14b003 Pokemon Emerald: Some dexsanity locations contribute evolution items (#3187)
* Pokemon Emerald: Change some dexsanity vanilla items to evo items

If a species evolves via item use (Fire Stone, Metal Coat, etc.), use that as it's vanilla item instead of a ball

* Pokemon Emerald: Remove accidentally added print

* Pokemon Emerald: Update changelog

* Pokemon Emerald: Adjust changelog

* Pokemon Emerald: Remove unnecessary else

* Pokemon Emerald: Fix changelog
2025-03-08 10:13:58 -05:00
CaitSith2
414ab86422 LttP: Fix dungeon counter options. (#4704) 2025-03-08 16:13:32 +01:00
Scipio Wright
d4e2698ae0 TUNIC: Add exception handling to deal with duplicate apworlds (#4634)
* Add exception handling to deal with duplicate apworlds

* Update worlds/tunic/__init__.py
2025-03-08 09:56:29 -05:00
JaredWeakStrike
3f8e3082c0 KH2: Client Optimizations and some QoL (#4547)
* adding qwints suggestions

* add stat increase protection and ingame yml stuff

* idk how I forgot these

* reword things

* Update worlds/kh2/Client.py

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

* 3.12 compat

* too long of a line

* why didnt I do this before lol

* reading is hard

* missed one

* forgot the self

* fix crash if you get datapackage that isnt kh2

* update to main?

* update to use 0.10 as base and fix violet's base 0 on hex values

* reverting this because I'm bad at my job

---------

Co-authored-by: qwint <qwint.42@gmail.com>
2025-03-08 08:58:59 -05:00
Justus Lind
0f738935ee Muse Dash: Update song list to Cosmic Radio. (#4554)
* MSR Anthology Vol.2 update

* Missing new line.

* Update to Cosmic Radio 2024
2025-03-08 08:58:26 -05:00
kbranch
9c57976252 LADX: Autotracker improvements (#4445)
* Expand and validate the RAM cache

* Part way through location improvement

* Fixed location tracking

* Preliminary entrance tracking support

* Actually send entrance messages

* Store found entrances on the server

* Bit of cleanup

* Added rupee count, items linked to checks

* Send Magpie a handshAck

* Got my own version wrong

* Remove the Beta name

* Only send slot_data if there's something in it

* Ask the server for entrance updates

* Small fix to stabilize Link's location when changing rooms

* Oops, server storage is shared between worlds

* Deal with null responses from the server

* Added UNUSED_KEY item
2025-03-08 13:32:45 +01:00
NewSoupVi
3e08acf381 The Witness: Move local_items code earlier #4696 2025-03-08 12:26:59 +01:00
Exempt-Medic
113259bc15 Update links (#4690)
* Update links

* Update two more
2025-03-07 20:17:45 -05:00
Natalie Weizenbaum
61afe76eae DS3: Remove the outdated French translation of the setup docs (#4700)
This was causing confusion and Discord support requests because the
instructions there are no longer compatible with the latest version of
Archipelago.

This also lists me as the primary author of the new setup guide.
2025-03-08 01:45:52 +01:00
NewSoupVi
08b3b3ecf5 The Witness: The Secret Feature (#4370)
* Secret Feature

* Fixes

* Fixes and unit tests

* renaming some variables

* Fix the thing

* unit test for elevator egg

* Docstring

* reword

* Fix duplicate locations I think?

* Remove debug thing

* Add the tests back lol

* Make it so that you can exclude an egg to disable it

* Improve hint text for easter eggs

* Update worlds/witness/options.py

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

* Update worlds/witness/player_logic.py

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

* Update worlds/witness/options.py

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

* Update worlds/witness/player_logic.py

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

* Update worlds/witness/rules.py

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

* Update test_easter_egg_shuffle.py

* This was actually not necessary, since this is the Egg requirements, nothing to do with location names

* Move one of them

* Improve logic

* Lol

* Moar

* Adjust unit tests

* option docstring adjustment

* Recommend door shuffle

* Don't overlap IDs

* Option description idk

* Change the way the difficulties work to reward playing higher modes

* Fix merge

* add some stuff to generate_data_file (this file is not imported during gen, don't review it :D)

* oop

* space

* This can be earlier than I thought, apparently.

* buffer

* Comment

* Make sure the option is VERY visible

* Some mypy stuff

* apparently ruff wants this

* .

* durinig

* Update options.py

* Explain the additional effects of each difficulty

* Fix logic of flood room secret

* Add Southern Peninsula Area

* oop

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2025-03-08 01:44:06 +01:00
Silent
bc61221ec6 TUNIC: Expanded hexagon quest options (#4076)
* More hex quest updates

- Implement page ability shuffle for hex quest
- Fix keys behind bosses if hex goal is less than 3
- Added check to fix conflicting hex quest options
- Add option to slot data

* Change option comparison

* Change option checking and fix some stuff

- also keep prayer first on low hex counts

* Update option defaulting

* Update option checking

* Fix option assignment again

* Show player name in option warning

* Add new option to universal tracker stuff

* Update __init__.py

* Make helper method for getting total hexagons in itempool

* Update options.py

* Update option value passthrough

* Change ability shuffle to default on

* Check for hexagons option when writing spoiler
2025-03-08 01:43:02 +01:00
threeandthreee
2f0b81e12c LADX: tarins gift improvement (#3970)
* add groups and a preset

* formatting

* pull zig's tarin's gift improvements

* typing

* alias groups for progressive items

* change tarins gift option a bit

* add bush breakers item group

* fix typo

* bush_breaker option, respect non_local_items

* review suggestions

* cleaner
thx exempt

* Update worlds/ladx/__init__.py

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

* fix gen failures for dungeon shuffle

* exclude shovel based on entrance mapping

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-03-08 01:24:58 +01:00
threeandthreee
bb9a6bcd2e LADX: more marin joke text (#3966)
* marin text

* Adds lots of Marin Flavour Text (#32)

* Updates of Splash text 24-09-18

* Re-Adds '

* use pkgutil

* Adds all community suggestions up until 20/09/2024 (#33)

* Adds all community suggestions up until 20/09/2024

* cutting deathlink jokes

---------

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

* drop piracy-adjacent jokes

* marin text was too long

* more submissions

* no longer looking for new maintainer

---------

Co-authored-by: palex00 <32203971+palex00@users.noreply.github.com>
2025-03-08 01:19:51 +01:00
Jérémie Bolduc
c8b7ef1016 Stardew Valley: Fix a logic bug where the Tea Sapling would be considered available without having the recipe (#4703) 2025-03-08 00:14:10 +01:00
Silent
e00467c2a2 TUNIC: Update logic for chest in fortress dark area (#4691)
* Update logic for beneath the vault chest

* use helper method instead

so that it checks the lanternless option
2025-03-06 00:18:27 +01:00
Silent
0eb6150e95 TUNIC: Fix rule for some grass in West Garden (#4682) 2025-03-06 00:17:27 +01:00
Fabian Dill
91d977479d Tests: test that collect and remove have expected behaviour. (#2062)
---------

Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2025-03-05 23:48:03 +01:00
BadMagic100
cd761db170 Core: Do GER speculative sweep membership checks against a set #4698 2025-02-27 19:21:48 +01:00
Aaron Wagener
026011323e The Messenger: Fix 0 Required Power Seals (#4692) 2025-02-27 11:42:41 -05:00
Silvris
adc5f3a07d MM2: Fix Shuffled Weaknesses Seed Bleed (#4689) 2025-02-27 11:13:37 -05:00
BadMagic100
69940374e1 Core: Only consider requested exits during ER placement and speculative sweep #4684 2025-02-27 17:12:35 +01:00
Scipio Wright
6dc461609b Noita: Fix bug with Traps disabled in 1-player games #4651 2025-02-23 17:27:05 +01:00
threeandthreee
58d460678e LADX: drop rupee farm condition (#4189)
* drop rupee farm condition

* cleanup

* rupee farm backup for all spending checks

* not power bracelet

* oops
2025-02-23 17:11:24 +01:00
Scipio Wright
0f7fd48cdd TUNIC: Add some more rules for Monastery connections (#4564)
* Move a couple locations to monastery

* Connect Quarry Back to Monastery

* Quarry Back -> Monastery with laurels, Monastery -> Monastery Back with wand/sword

* Add Monastery Back region

* Move a couple non-ER locations to monastery back

* Monastery front -> back with sword, wand, or laurels zip

* also laurels zip for non-ER
2025-02-23 17:02:30 +01:00
Natalie Weizenbaum
18de035b4d DS3: Update setup documentation (#4437) 2025-02-22 08:33:58 -05:00
Fabian Dill
11fa43f0a4 Factorio: prevent players from getting stuck from Teleport Traps (#4537) 2025-02-20 00:17:19 +01:00
black-sliver
91a8fc91d6 CI: fix native tests toolchain on windows (#4668)
* CI: ctest: fix trigger on CMakeLists change

* CI: ctest: update cmake version

this removes a warning
and matches gtest

* CI: ctest: remove explicit build mode for MSVC

gtest switched to dynamic libc (/MD), which is default, so this just works now
2025-02-19 13:50:25 +01:00
Fabian Dill
15bde56551 Factorio: prevent invalid starting items count (#4658) 2025-02-17 18:58:38 +01:00
NewSoupVi
d744e086ef MultiServer: Fix hinting an item that someone else already hinted in their slot not resolving correctly (#4655)
* Fix get_hint not checking for finding_player

* Fix using the wrong variable for slot lookup
2025-02-17 15:16:18 +01:00
Scipio Wright
378fa5d5c4 Fix gun missing from combat_items, add new for combat logic cache, very slight refactor of check_combat_reqs to let it do the changeover in a less complicated fashion, fix area being a boss area rather than non-boss area for a check (#4657) 2025-02-17 01:30:40 +01:00
black-sliver
8349774c5c customserver: ignore static datapackage optimization for old games (#4650) 2025-02-16 23:51:36 +01:00
qwint
34795b598a GER: Use Itempool Count for Minimal handling (#4649)
* uses itempool count vs unfilled location count instead of counting prog_items values which could have custom counters

* move unfilled location check to before can_reach

* add tests for successful minimal GER call with extra collect override prog_items in the pool to regression test issue fixed in this PR
2025-02-16 20:21:09 +01:00
JoshuaEagles
efd5004330 Docs: Update SA2B Linux and Steam Deck Setup Guide + Add Celeste 64 Linux Setup Guide (#4593)
* Update Linux and Steam Deck setup guide for sa2b

* Add Linux and Steam Deck setup guide for Celeste 64
2025-02-12 17:47:43 +01:00
Matthew Wells
c799531105 Docs: Add missing plural in faq (#4622) 2025-02-12 17:47:17 +01:00
threeandthreee
5c1ded1fe9 LADX: bomb as logical bush breaker #4636 2025-02-12 17:46:43 +01:00
qwint
b2162bb8e6 Docs: clean up create_item/event example (#4596)
* eyes

* remove line wraps where unnecessary
2025-02-12 17:46:07 +01:00
agilbert1412
f1769a8d00 Stardew Valley: Fixed Powdermelon and option inconsistencies (#4632)
* - Fixed powdermelon season

* - Improve cohesion in presets

* - Update several tooltips to be more consistent and accurate
2025-02-12 17:45:03 +01:00
qwint
f520c1d9f2 Launcher: Allow for --nogui client launches (#4549) 2025-02-10 19:34:27 +01:00
PinkSwitch
910369a7f8 Bizhawk Client: Display Err (#4532)
Co-authored-by: Bryce Wilson
2025-02-10 19:27:10 +01:00
qwint
dbf6b6f935 CC: don't try to reconnect on invalid version (#4606) 2025-02-10 19:23:58 +01:00
qwint
e9c463c897 CC: Force Text Client to always connect with empty game (#4607) 2025-02-10 19:23:09 +01:00
qwint
f4e43ca9e0 LttP: mock world.random in adjuster (#4623) 2025-02-10 19:22:06 +01:00
Fabian Dill
a298be9c41 Core: change HINT_FOUND to 40 and HINT_UNSPECIFIED to 0 (#4620) 2025-02-10 19:19:00 +01:00
Fabian Dill
18bcaa85a2 Test: ensure get_all_state() does not error in between steps (#4612) 2025-02-10 19:18:14 +01:00
Scipio Wright
359f45d50f TUNIC: Combat logic fix (#4589)
* Potential fix for attack issue

* also put the lazy version of the swamp fix in for good measure

* fix extra line

* now it is good

* Add the test, roll the other PR into this one

* Make the test exception more useful

* Remove debug print

* Combat logic fixed?

* Move a few areas to before well instead of east forest

* Put in qwint's suggestions in test

* Implement qwint's suggestions in combat_logic.py

* Implement qwint's suggestions for combat_logic.py

* Fix typo

* Remove experimental from combat logic description

* Remove copy_mixin again

* Add comment about copy_mixin

* Use a more proper random

* Some optimizations from Vi's comments
2025-02-09 19:12:17 +01:00
qwint
f5c574c37a Settings: add format handling to yaml exception marks for readability (#4531) 2025-02-09 12:11:27 +01:00
NewSoupVi
f75a1ae117 KH2: Fix lambda capture issue with weapon slot logic (#4604)
* KH2: Fix lambda capture issue with weapon slot logic

* Update Rules.py

* Improved by JaredWeakStrike (#4605)

* Apparently this wasn't meant to be indented

---------

Co-authored-by: JaredWeakStrike <96694163+JaredWeakStrike@users.noreply.github.com>
2025-02-08 00:06:04 +01:00
Kory Dondzila
768ccffe72 Shivers: Update shivers links and guides (#4592) 2025-02-07 21:06:06 +01:00
Martmists
f6668997e6 [AHIT] Fix small options issue (#4615) 2025-02-07 21:02:37 +01:00
shananas
db11c620a7 KH2 Doc Update #4609
Mod Manager Version Number
2025-02-04 17:09:02 +01:00
Jouramie
da48af60dc Stardew Valley: add assert_can_reach_region_* for better tests (#4556)
* add assert_reach_region_*; refactor existing assert_reach_location_* to allow string

* rename asserts
2025-02-04 08:27:23 +01:00
massimilianodelliubaldini
19faaa4104 Core: Fix #4595 by using first type's docstring in a union type (#4600)
* Fix #4595: use first type's docstring in a union type.

* Reuse existing import.
2025-02-04 01:49:07 +01:00
Scipio Wright
628252896e TUNIC: Call Combat Logic experimental (#4594)
* Update options.py

* Update options.py
2025-02-03 15:53:56 +01:00
Mysteryem
f28aff6f9a Core: Replace generator creation/iteration in CollectionState methods (#4587)
* Core: Replace generator creation/iteration in CollectionState methods

Using generators in these functions incurs overhead to create the new
generator instance, call the `any`/`all`/`sum` function and have the
`any`/`all`/`sum` function iterate the generator, which in turn iterates
the iterable.

Replacing the use of generators with for loops is faster.

Getting `self.prog_items[player]` once in advance also improves
performance of iterating longer iterables.

* Add comment on the choice of for loops instead of any()/all()/sum()
2025-02-02 15:25:34 +01:00
Fabian Dill
894732be47 kvui: set home folder to non-default (#4590)
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2025-02-02 02:53:16 +01: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 a7a546ed3f.

* 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 719255891e.
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 7c2b3df617.

* 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 34f2c1aed8.

* 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 9290191cb3.

* 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 c2f7d674d3.

* 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 7c2b3df617.

* 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 34f2c1aed8.

* 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 9290191cb3.

* 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 c2f7d674d3.

* Revert "Textual fixes and changes"

This reverts commit e9432f9245.

* 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 68804fef14.

* 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 e178a7c0a6.

* 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 a2360fe197, reversing
changes made to b8948bc495.

* 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 df58bbcd99.

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

This reverts commit 0f4d441824.

* 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 e178a7c0a6.

* 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 a2360fe197, reversing
changes made to b8948bc495.

* 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 df58bbcd99.

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

This reverts commit 0f4d441824.

* 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 7c2b3df617.

* 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 34f2c1aed8.

* 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 9290191cb3.

* 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 c2f7d674d3.

* Revert "Textual fixes and changes"

This reverts commit e9432f9245.

* 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 7c2b3df617.

* 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 34f2c1aed8.

* 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 9290191cb3.

* 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 7c2b3df617.

* 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 34f2c1aed8.

* 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 9290191cb3.

* 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 759efd3e2b.

* 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 ecbf986145.

* 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 bb08c3f0c2.

* 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 630a3bdfb9
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 7c2b3df617.

* 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 34f2c1aed8.

* 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 9290191cb3.

* 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 7c2b3df617.

* 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 34f2c1aed8.

* 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 9290191cb3.

* 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 bb08c3f0c2.

* 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 630a3bdfb9
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 ecbf986145.

* 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 e178a7c0a6.

* 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 a2360fe197, reversing
changes made to b8948bc495.

* 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 df58bbcd99.

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

This reverts commit 0f4d441824.

* 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
Fabian Dill
75bef3ddb1 Various: fix absolute imports in worlds (#3489) 2024-06-11 00:42:57 +02:00
JusticePS
484082616f Adventure: Update to use new options api (#3326) 2024-06-11 00:42:01 +02:00
Aaron Wagener
35617bdac5 Tests: Add checksum validation to the postgen datapackage test (#3456)
* Tests: Add checksum validation to the postgen datapackage test

* add a special case for the test world datapackage rather than hidden

* add the test world to the datapackage instead of special casing around it

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
2024-06-10 09:28:28 +02:00
Phaneros
0a912808e3 SC2: update inno_setup.iss to remove old sc2wol world folder (#3495) 2024-06-10 02:05:39 +02:00
Phaneros
84a6d50ae7 sc2: Fixed sc2 client's /received command breaking after PR 1933 merged (#3497) 2024-06-09 16:55:05 +02:00
jamesbrq
5f8a8e6dad Update Rom.py (#3498) 2024-06-09 16:54:07 +02:00
Phaneros
2198a70251 Core: CommonClient: command history and echo (#3236)
* client: Added command history access with up/down and command echo in common client

* client: Changed command echo colour to orange

* client: removed star import from typing

* client: updated code style to match style guideline

* client: adjusted ordering of calling parent constructor in command prompt input constructor

* client: Fixed issues identified by beauxq in PR; fixed some typing issues

* client: PR comments; replaced command history list with deque
2024-06-09 04:08:47 +02:00
Fabian Dill
c478e55d7a Generate: improve logging capture (#3484) 2024-06-09 03:13:27 +02:00
Fabian Dill
76804d295b Core: explicitly import importlib.util (#3224) 2024-06-08 20:04:17 +02:00
Fabian Dill
0d9fce29c6 Core: load frozen decompressed worlds (#3488) 2024-06-08 19:58:58 +02:00
black-sliver
302017c69e Test: hosting: handle writes during start_room (#3492)
Note: maybe we'd also want to add such handling to WebHost itself,
      but this is out of scope for getting hosting test to work.
2024-06-08 17:51:09 +02:00
qwint
a0653cdfe0 HK: adds split movement items to skills item group (#3462) 2024-06-08 17:31:27 +02:00
Fabian Dill
89d584e474 WebHost: allow getting checksum-specific datapackage via /api/datapackage/<checksum> (#3451)
* WebHost: allow getting checksum-specific datapackage via /api/datapackage/<checksum>

* match import style of /api/generate
2024-06-08 05:07:14 -04:00
Chris Wilson
39deef5d09 Fix Choice and TextChoice options crashing WebHost if the option's default value is "random" (#3458) 2024-06-08 04:54:14 -04:00
Exempt-Medic
b3a2473853 Docs: Fixing subject-verb agreement (#3491) 2024-06-08 05:47:02 +02:00
qwint
b053fee3e5 HK: adds schema to validate plando charm costs (#3471) 2024-06-07 19:12:10 +02:00
Trevor L
8c614865bb Bomb Rush Cyberfunk: Fix missing location (#3475) 2024-06-07 19:11:35 +02:00
Silent
d72afe7100 Update setup_en.md (#3483) 2024-06-07 17:45:22 +02:00
chandler05
223f2f5523 A Short Hike: Update installation instructions (#3474)
* A Short Hike: Update installation instructions

* Update setup_en.md

* Update setup_en.md

* Change link
2024-06-06 22:57:50 +02:00
Scipio Wright
31419c84a4 TUNIC: Remove rule for west Quarry bomb wall (#3481)
* Update west quarry bomb wall rule

* Update west quarry bomb wall rule
2024-06-06 22:56:35 +02:00
Doug Hoskisson
6bb1cce43f Core: hot reload components from installed apworld (#3480)
* Core: hot reload components from installed apworld

* address PR reviews

`Launcher` widget members default to `None` so they can be defined in `build`

`Launcher._refresh_components` is not wrapped

loaded world goes into `world_sources` so we can check if it's already loaded.
(`WorldSource` can be ordered now without trying to compare `None` and `float`)
(don't load empty directories so we don't detect them as worlds)

* clarify that the installation is successful
2024-06-06 20:36:14 +02:00
black-sliver
808f2a8ff0 Core: update dependencies (#3477) 2024-06-06 19:27:01 +02:00
Doug Hoskisson
7f1e95c04c Core: gitignore custom_worlds (#3479) 2024-06-06 09:02:29 +02:00
NewSoupVi
86da3eb52c Remove all functools lru cache (#3446) 2024-06-06 03:40:47 +02:00
black-sliver
afb6d9c4da MultiServer, customserver, CI, Test: Fix problems in room hosting and test/simulate it (#3464)
* Test: add hosting simulation test

* WebHost: add weak typing to get_app()

* MultiServer: add typing to auto_saver_thread

* MultiServer: don't cancel task, properly end it

* customserver: stop auto-save thread from saving after shutdown

and make sure it stops, another potential memory leak

* MultiServer, customserver: make datapackage small again

* customserver: collect/finish room tasks

Hopefully fixes the memory leak we are seeing

* CI: test hosting

* Test: hosting: verify autohoster saves on Ctrl+C

* customserver: save when stopping via Ctrl+C
2024-06-06 01:54:46 +02:00
black-sliver
911eba3202 WebHost: update dependencies (#3476) 2024-06-06 01:51:05 +02:00
Fabian Dill
93cd13736a Launcher: handle apworld installation (#3472) 2024-06-06 01:36:02 +02:00
chandler05
c554c3fdae A Short Hike: Add new options and option groups (#3410)
* A Short Hike: New options and stuff

* Add to slot data for poptracker

* Address concerns

* Address concerns

* Fix indentations

* Update option description

* Address all issues

* Group "or"s
2024-06-06 00:50:30 +02:00
Aaron Wagener
be03dca774 Core: add unit tests and more documentation for numeric options (#2926)
* Core: add unit tests for the numeric options

* document using a collection and the hashing quirk

* add another example for the footgun

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-06-06 00:17:52 +02:00
Fabian Dill
04ec2f3893 Setup: delete old world folders (#3469) 2024-06-05 22:26:13 +02:00
Fabian Dill
afe4b2925e Setup: rename ArchipelagoLauncher(DEBUG) to ArchipelagoLauncherDebug (#3468) 2024-06-05 21:00:53 +02:00
qwint
da2f0f94ca HK: lower max egg cost (#3463) 2024-06-05 00:01:22 -05:00
Doug Hoskisson
6a60a93092 Zillion: fix some game over bugs (#3466)
There was a bug that made lots of flashing terrain if a game over happened in certain places.
(And this could be dangerous for people sensitive to flashing lights.)

There was also a bug with a bad sound effect after a game over.
2024-06-04 21:56:32 -07:00
Doug Hoskisson
76266f25ef Core: Launcher: can drag-and-drop patch on Launcher window (#3442)
* Core: Launcher: can drag-and-drop patch on Launcher window

* doc string for `_on_drop_file`
2024-06-05 01:54:21 +02:00
Aaron Wagener
3cc391e9a1 Docs: Add detail on customizing the forced groups (#3371)
* Docs: Fix incorrect assertion in option group docs and add detail on customizing the forced groups.

* add docs for the visibility attribute

* typos

* review comments

* missed one

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

* better wording

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-04 21:52:07 +02:00
Justus Lind
133167564c Muse Dash: Option Groups and Options Rework (#3434)
* Ensure that included/starter songs only include those within enabled dlcs.

* Allow filtering traps by trap instead of by category.

* Add in the currently available limited time dlcs to the dlc list.

* Add the option group to the webhost and cleanup some errors.

* Fix trap list.

* Update tests. Add new ones to test correctness of new features.

* Remove the old Just As Planned option

* Make traps order alphabetically. Also adjust the title for traps.

* Adjust new lines to better fit the website.

* Style fixes.

* Test adjustments and a fix due to test no longer having just as planned dlc.

* Undo spacing changes as it breaks yaml generation.

* Fix indenting in webhost.

* Add the old options in as removed. Also clean up unused import.

* Remove references to the old allow_just_as_planned_dlc_songs option in Muse Dash tests.

* Add newline to end of file.

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-06-04 21:45:26 +02:00
Rjosephson
f30f2d3a3f RoR2: Add Support for New Stage (#3436)
* add support for the new stage added to RoR2

* Fix stage being unreachable

* add option groups

* reorder option groups
2024-06-04 21:24:14 +02:00
Bryce Wilson
ee1b13f219 Pokemon Emerald: Fix possible dexsanity/legendary hunt softlock (#3443)
* Pokemon Emerald: Remove mirage tower from allowed dexsanity maps

* Pokemon Emerald: Prevent placing wailord/relicanth in out of logic maps

* Pokemon Emerald: Clarify docstring

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

* Pokemon Emerald: Update changelog

---------

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-06-04 21:21:58 +02:00
Exempt-Medic
c4572964ec KH2: Fixing Start Inventory bug, limiting CustomItemPool keys, fixing two typos (#3444)
* Fixing inclusion checking error

* Fixing typo, limiting valid keys to valid keys

* Adding space

* Add period
2024-06-04 21:20:37 +02:00
CookieCat
16ae8449f4 AHIT: Fix Death Wish location rules not being added properly (#3455)
* 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 e178a7c0a6.

* 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 a2360fe197, reversing
changes made to b8948bc495.

* 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

* formatting

* major logic bug fix for death wish

---------

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-06-04 21:15:28 +02:00
Scipio Wright
c4e0b17de3 TUNIC: Add ice grapple logic to get to gauntlet (#3459) 2024-06-04 21:14:29 +02:00
Bryce Wilson
0265f4d809 BizHawkClient: Reset finished_game if ROM changes (#3246) 2024-06-04 14:06:41 +02:00
Chris Wilson
06e65c1dc6 WebHost: weighted-options bugfixes (#3448)
* Fix improper css for word-break on player-options page

* Add default handling to weighted-options types

* Remove random-low/mid/high from Toggle, Choice, and TextChoice,

* Port key sorting for OptionList and OptionSet from player-options to weighted-options

* Ensure Choice and TextChoice values are set properly

* Remove debug line 🤦‍♂️
2024-06-03 18:43:01 -04:00
Exempt-Medic
c7eef13b33 Accounting for name change (#3449) 2024-06-03 16:36:51 +02:00
Star Rauchenberger
fb2c194e37 Lingo: Fix Basement access with THE MASTER (#3231) 2024-06-03 03:51:27 -05:00
Zach Parks
cff7327558 Utils: Fix mistake made with KeyedDefaultDict from #1933 that broke tracker functionality. (#3433) 2024-06-03 03:45:01 -05:00
Scipio Wright
70e9ccb13c TUNIC: Fix plando connections, seed groups, and UT support (#3429) 2024-06-03 03:44:37 -05:00
Exempt-Medic
d9120f0bea WebHost: Allowing options that work on WebHost to be used in presets (#3441) 2024-06-03 03:42:27 -05:00
Remy Jette
424c8b0be9 Pokemon RB: Add an item group for each HM to improve hinting (#3311)
* Pokemon RB: Add an item group for each HM

HMs are suffixed with the name of the move, e.g. "HM02 Fly". If TM
move are randomized, they do not have the move name, e.g. "TM02".

If someone hints for an HM using the just the number, the fuzzy matching
sees "TM02" as closer than "HM02 Fly", and in fact sees it as close
enough to not ask the user to confirm, leading them to waste hint points
on non-progression item that they didn't intend.

Emerald already does this for this reason, adding the same for RB.

* Add the new groups for HMs in the item_table instead
2024-06-03 04:42:15 +02:00
qwint
6432560fe5 Fix Egg_Shop typo in costsanity (#3447) 2024-06-03 04:39:34 +02:00
Emily
dedabad290 APSudoku: take over maintaining hintgame sudoku from bk_sudoku (#3432) 2024-06-02 11:45:46 -05:00
NewSoupVi
e49b1f9fbb The Witness: Automatic Postgame & Disabled Panels Calculation (#2698)
* Refactor postgame code to be more readable

* Change all references to options to strings

* oops

* Fix some outdated code related to yaml-disabled EPs

* Small fixes to short/longbox stuff (thanks Medic)

* comment

* fix duplicate

* Removed triplicate lmfao

* Better comment

* added another 'unfun' postgame consideration

* comment

* more option strings

* oops

* Remove an unnecessary comparison

* another string missed

* New classification changes (Credit: Exempt-Medic)

* Don't need to pass world

* Comments

* Replace it with another magic system because why not at this point :DDDDDD

* oops

* Oops

* Another was missed

* Make events conditions. Disable_Non_Randomized will no longer just 'have all events'

* What the fuck? Has this just always been broken?

* Don't have boolean function with 'not' in the name

* Another useful classification

* slight code refactor

* Funny haha booleans

* This would create a really bad merge error

* I can't believe this actually kind of works

* And here's the punchline. + some bugfixes

* Comment dat code

* Comments galore

* LMAO OOPS

* so nice I did it twice

* debug x2

* Careful

* Add more comments

* That comment is a bit unnecessary now

* Fix overriding region connections

* Correct a comment

* Correct again

* Rename variable

* Idk I guess this is in this branch now

* More tweaking of postgame & comments

* This is commit just exists to fix that grammar error

* I think I can just fucking delete this now???

* Forgot to reset something here

* Delete dead codepath

* Obelisk Keys were getting yote erroneously

* More comments

* Fix duplicate connections

* Oopsington III

* performance improvements & cleanup

* More rules cleanup and performance improvements

* Oh cool I can do this huh

* Okay but this is even more swag tho

* Lazy eval

* remove some implicit checks

* Is this too magical yet

* more guard magic

* Maaaaaaaagiccccccccc

* Laaaaaaaaaaaaaaaazzzzzzyyyyyyyyyyy

* Make it docstring

* Newline bc I like that better

* this is a little spooky lol

* lol

* Wait

* spoO

* Better variable name and comment

* Improved comment again

* better API

* oops I deleted a deepcopy

* lol help

* Help???

* player_regionsns lmao

* Add some comments

* Make doors disabled properly again. I hope this works

* Don't disable lasers

* Omega oops

* Make Floor 2 Exit not exist

* Make a fix that's warps compatible

* I think this was an oversight, I tested a seed and it seems to have the same result

* This is definitely less Violet than before

* Does this feel more violet lol

* Exception if a laser gets disabled, cleanup

* Ruff

* >:(

* consistent utils import

* Make autopostgame more reviewable (hopefully)

* more reviewability

* WitnessRule

* replace another instance of it

* lint

* style

* comment

* found the bug

* Move comment

* Get rid of cache and ugly allow_victory

* comments and lint
2024-06-01 23:11:28 +02:00
Fabian Dill
da33d1576a WebHost: update trackers only if they're visible. (#3407) 2024-06-01 17:07:58 +02:00
Fabian Dill
13bc121c27 Webhost: Sphere Tracker (#3412) 2024-06-01 14:43:11 +02:00
Fabian Dill
bbc79a5b99 LttP: allow Triforce Piece as start inventory item (#3292) 2024-06-01 14:38:45 +02:00
Ishigh1
3cb5452455 Core: Fix auto-fill in the text client when clicking on a hint suggestion (#3267) 2024-06-01 07:32:41 -05:00
Nicholas Saylor
8dbc8d2d41 Installer: Prevent ALTTP Sprite Download from being Interrupted (#3293) 2024-06-01 06:42:02 -05:00
Dinopony
1e205f9d73 Landstalker: Fixed rare generation issues (#3353)
Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2024-06-01 06:39:57 -05:00
Exempt-Medic
97c9c5310b PKMN R/B: Fixing Key Items Only + Removed Exp. All (#3420) 2024-06-01 06:35:33 -05:00
Silvris
4e5b6bb3d2 Core: move PlandoConnections and PlandoTexts to the options system (#2904)
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: Scipio Wright <scipiowright@gmail.com>
Co-authored-by: beauxq <beauxq@yahoo.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
2024-06-01 06:34:41 -05:00
Bryce Wilson
f40b10dc97 Pokemon Emerald: Adjust options (#3278) 2024-06-01 06:14:40 -05:00
NewSoupVi
4cab3b6371 The Witness: Put Treehouse Both Orange Bridges EP on the normal EPs exclusion list (#3308) 2024-06-01 06:13:00 -05:00
Bryce Wilson
67cd32b37c Pokemon Emerald: Use self.player_name (#3384) 2024-06-01 06:12:37 -05:00
Rensen3
91c89604a5 YGO06: prevent multiple players affecting each others procedure patch (#3409) 2024-06-01 06:10:02 -05:00
Louis M
f2587d5d27 Aquatia: Locations name changed due to typo's, grammar, or inconsistencies (#3421) 2024-06-01 06:09:34 -05:00
Exempt-Medic
2a5de8567e Docs: Making option description more readable and accurate (#3426) 2024-06-01 06:07:43 -05:00
Zach Parks
5aa6ad63ca Core: Remove Universally Unique ID Requirements (Per-Game Data Packages) (#1933) 2024-06-01 06:07:13 -05:00
Chris Wilson
f3003ff147 Fix options pages sometimes displaying blank values in form fields (#3364) 2024-05-31 22:41:49 -04:00
Chris Wilson
15e06e1779 Fix TextChoice options sometimes creating a broken YAML (#3390)
* Fix TextChoice options with custom values improperly being included in YAML output

* Update WebHostLib/options.py

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

---------

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
2024-05-31 22:41:03 -04:00
Exempt-Medic
b055a39454 PKMN R/B: "J.r" -> "Jr." (#3423) 2024-05-31 14:48:21 -05:00
BadMagic100
7058575c95 Hollow Knight: Add missing comma (#3403) 2024-05-30 19:57:54 +02:00
Salzkorn
2fe8c43351 SC2: Fix Kerrigan Primal Form on Half Completion (#3419) 2024-05-30 18:52:01 +02:00
black-sliver
6f6bf3c62d CustomServer: properly 'inherit' Archipelago from static_server_data (#3366)
This fixes a potential exception during room spin-up.
2024-05-30 18:16:13 +02:00
Witchybun
378af4b07c Stardew Valley: Fix magic altar logic (#3417)
* Fix magic altar logic

* Force a tuple (really?)

* Fix received and force progression on all spells

* Reversing the tuple change (?yllaer)
2024-05-29 20:16:19 +02:00
Zach Parks
34f903e97a CODEOWNERS: Remove @jtoyoda as world maintainer for Final Fantasy (#3398) 2024-05-29 09:59:40 -05:00
Fabian Dill
e31a7093de WebHost: use settings defaults for /api/generate and options -> Single Player Generate (#3411) 2024-05-29 16:53:18 +02:00
neocerber
527559395c Docs, Starcraft 2: Add French documentation for setup and game page (#3031)
* Started to create the french doc

* First version of sc2 setup in french finish, created the file for the introduction of the game in french

* French-fy upgrade in setup, continue translation of game description

* Finish writing FR game page, added a link to it on the english game page. Re-read and corrected both the game page and setup page.

* Corrected a sentence in the SC2 English setup guide.

* Applied 120 carac limits for french part, applied modification for consistency.

* Added reference to website yaml checker, applied several wording correction/suggestions

* Modified link to AP page to be in relative (fr/en), uniformed SC2 and random writing (fr), applied some suggestons in writing quality(fr), added a mention to the datapackage (fr/en), enhanced prog balancing recommendation (fr)

* Correction of some grammar issues

* Removed name correction for english part since done in other PR; added mention to hotkey and language restriction

* Applied suggestions of peer review

* Applied mofications proposed by reviewer about the external website

---------

Co-authored-by: neocerber <neorcerber@gmail.com>
2024-05-29 03:48:52 +02:00
Aaron Wagener
649ee117da Docs: improve contributing sign posting (#2888)
* Docs: improve sign posting for contributing

* fix styling as per the style guide

* address review comments

* apply medic's feedback
2024-05-29 03:46:17 +02:00
qwint
5b34e06c8b adds godtuner to prog and requires it for godhome flower quest manually (#3402) 2024-05-29 03:37:44 +02:00
Seldom
04e9f5c47a Migrate Terraria to new options API (#3414) 2024-05-28 20:37:07 +02:00
Aaron Wagener
dfc347cd24 Core: add options to the list of valid names instead of deleting game weights (#3381) 2024-05-27 23:52:23 +02:00
Fabian Dill
74aa4eca9d MultiServer: make !hint prefer early sphere (#2862) 2024-05-27 18:43:25 +02:00
Justus Lind
df877a9254 Muse Dash: 4.4.0 (#3395) 2024-05-27 02:27:43 +02:00
Bryce Wilson
70d97a0eb4 BizHawkClient: Add suggestion when no handler is found (#3375) 2024-05-27 02:27:04 +02:00
black-sliver
f249c36f8b Setup: pin cx_freeze to 7.0.0 (#3406)
7.1.0 is broken on Linux when using pygobject, which we use as optional dependency for kivy.
2024-05-26 21:22:40 +02:00
NewSoupVi
61e88526cf Core: Rename "count_exclusive" methods to "count_unique" (#3386)
* rename exclusive to unique

* lint

* group as well
2024-05-25 13:14:13 +02:00
Exempt-Medic
18390ecc09 Witness: Fix option description (#3396)
* Fixing description

* Another mistake
2024-05-24 19:32:23 +02:00
Aaron Wagener
8045c8717c Webhost: Allow Option Groups to specify whether they start collapsed (#3370)
* allow option groups to specify whether they should be hidden or not

* allow worlds to override whether game options starts collapsed

* remove Game Options assert so the visibility of that group can be changed

* if "Game Options" or "Item & Location Options" groups are specified, fix casing

* don't allow item & location options to have duplicates of the auto added options

* use a generator instead of a comprehension

* use consistent naming
2024-05-24 01:18:21 -04:00
NewSoupVi
613e76689e CODEOWNERS: Actually link the correct person for Yu Gi Oh (#3389) 2024-05-23 20:25:41 -05:00
Exempt-Medic
2a47f03e72 Docs: Update trigger guide and advanced yaml guide (#3385)
* I guess these don't exist anymore

* Update worlds/generic/docs/advanced_settings_en.md

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

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
2024-05-23 20:36:45 -04:00
Aaron Wagener
8b992cbf00 Webhost: Disallow empty option groups (#3369)
* move item_and_loc_options out of the meta class and into the Options module

* don't allow empty world specified option groups

* reuse option_group generation code instead of rewriting it

* delete the default group if it's empty

* indent
2024-05-23 18:50:40 -04:00
Doug Hoskisson
d09b214309 Core: Utils.py typing (#3064)
* Core: Utils.py typing

`get_fuzzy_results` typing

There are places that this is called with a `word_list` that is not a `Sequence`, and it is valid (e.g., `set` or `dict`).

To decide the right type, we look at how `word_list` is used:
- the parameter to `len` - requires `__len__`
- the 2nd parameter to `map` - requires `__iter__`

Then we look at https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes and ask what is the simplest type that includes both `__len__` and `__iter__`: `Collection`

(Python 3.8 requires using the alias in `typing`, instead of `collections.abc`)

* a bit more typing and cleaning

* fine, take away my fun for something that no one is ever going to see anyway...

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-05-23 19:55:45 +02:00
Fabian Dill
860ab10b0b Generate: remove tag "-" (#3036)
* Generate: introduce Remove, similar to Merge

* make + dict behave as + for each value


---------

Co-authored-by: Zach Parks <zach@alliware.com>
2024-05-23 15:03:21 +02:00
CookieCat
3f8c348a49 AHIT: Fix Your Contract has Expired being placed on the first level when it shouldn't (#3379) 2024-05-23 09:49:17 +02:00
Zach Parks
e1ff5073b5 WebHost, Core: Move item and location descriptions to WebWorld responsibilities. (#2508)
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
Co-authored-by: el-u <109771707+el-u@users.noreply.github.com>
2024-05-23 02:08:08 -05:00
Star Rauchenberger
8b6eae0a14 Lingo: Add option groups (#3352)
* Lingo: Add option groups

* Touched up option docstrings
2024-05-23 02:22:39 +02:00
agilbert1412
89d0dae299 Stardew valley: Create Option Groups (#3376)
* - Fix link in Stardew Setup Guide

* - Create option groups for Stardew Valley

* - Cleaned up the imports

* - Fixed double quotes and trailing comma

* - Improve order in the multipliers category
2024-05-23 02:22:28 +02:00
LiquidCat64
56d01f3913 CV64: Add option groups (#3360)
* Add the option groups.

* Get rid of all mid-sentence line breaks.
2024-05-23 02:16:13 +02:00
Scipio Wright
a43e294786 TUNIC: Add option presets (#3377)
* Add option presets

* why the hell is there an s here

* entrance rando yes
2024-05-23 02:12:59 +02:00
Justus Lind
92392c0e65 Update Song List to Muse Dash 4.3.0 (#3216) 2024-05-23 02:11:27 +02:00
Star Rauchenberger
893a157b23 Lingo: Minor logic fixes (part 2) (#3250)
* Lingo: Minor logic fixes (part 2)

* Update the datafile

* Renamed Fearless Mastery

* Move Rhyme Room LEAP into upper room

* Rename Artistic achievement location

* Fix broken wondrous painting

* Added a test for the Wondrous painting thing
2024-05-23 02:09:52 +02:00
Scipio Wright
02d3fdf2a6 Update options to look better on webhost after update, also give death link a description (#3329) 2024-05-23 02:05:21 +02:00
Bryce Wilson
cd160842ba BizHawkClient: Linting/style (#3335) 2024-05-23 02:03:42 +02:00
Bryce Wilson
93f63a3e31 Pokemon Emerald: Fix broken Markdown in spanish setup guide (#3320)
* Pokemon Emerald: Fix broken Markdown in spanish setup guide

* Pokemon Emerald: Minor formatting in spanish setup guide

* oops
2024-05-23 02:01:27 +02:00
Scipio Wright
b4fec93c82 Update guide with some linux instructions (#3330) 2024-05-23 02:00:06 +02:00
Exempt-Medic
1ae0a9b76f WebHost: Fixing default values for LocationSets (#3374)
* Update macros.html

* Update macros.html
2024-05-23 01:58:06 +02:00
Fabian Dill
0ea20f3929 Core: add panic_method setting (#3261) 2024-05-22 14:02:18 +02:00
PoryGone
20134d3b1e Celeste 64: Option Groups (#3321)
* Celeste 64: Option Groups

* Retarget OptionGroup import
2024-05-21 18:22:39 -04:00
PoryGone
a1c2e8715e DKC3: Option Groups (#3322)
* DKC3: Option Groups

* Retarget OptionGroup import
2024-05-21 18:19:37 -04:00
NewSoupVi
61be79b7ea The Witness: Option Groups & Tooltip formatting (#3342)
* Add option groups

* Option tooltip formatting

* eof

* reindent, apparently I'm stupid

* lint

* oops indent
2024-05-21 18:17:12 -04:00
Scipio Wright
e7544d835c TUNIC: Add option groups, fix option descriptions (#3344)
* Add option groups, fix up option descriptions

* Change sword progression description back

* Add missed newline change, missed space after asterisk
2024-05-21 18:12:52 -04:00
PoryGone
62e68ba1cc SMW: Option Groups and Presets (#3345)
* SMW: Add Option Groups and Presets

* Fix Boss Shuffle Preset

* Tooltip formatting
2024-05-21 18:09:05 -04:00
Trevor L
9441cc31b7 Hylics 2: Update option docstrings (#3359)
* Update Options.py

* "pool" -> "item pool"
2024-05-21 17:53:00 -04:00
PoryGone
5c66681233 SA2B: Option Groups and Dataclass (#3357)
* Merge Conflicts

* SA2B: Option Groups

* Re-add erroneously-removed import
2024-05-21 17:48:23 -04:00
Trevor L
92b1f3cd19 Bomb Rush Cyberfunk: Update option docstrings (#3358)
* Update Options.py

* Update Options.py
2024-05-21 17:31:01 -04:00
jamesbrq
514ad69f44 Remove logging from validate_rom (#3362) 2024-05-21 20:57:59 +02:00
Fabian Dill
461f5db35a Customserver: only save on exit if it's in a good state. (#3351) 2024-05-21 14:08:59 +02:00
CookieCat
fe7bc8784d A Hat in Time: Implement New Game (#2640)
Adds A Hat in Time as a supported game in Archipelago.
2024-05-20 09:04:06 +02:00
Louis M
c792ae76ca Aquaria: Adding Aquaria to README and some other minors changes (#3313) 2024-05-20 08:58:44 +02:00
Chris Wilson
bfe215d5a7 Use world.web.options_presets directly instead of creating an empty dict first (#3348) 2024-05-20 01:57:07 -04:00
Chris Wilson
5910b94deb Update options pages macros to respect valid_keys for item and location options (#3347) 2024-05-20 00:26:42 -04:00
Fabian Dill
14ffd1c70c Subnautica: fix use of _valid_keys were valid_keys should be used. (#3346)
* Subnautica: fix use of _valid_keys were valid_keys should be used.

* Update Options.py
2024-05-20 00:20:01 -04:00
Scipio Wright
754fc11c1b TUNIC: ER Refactor for better plando connections, fewer shops improvement (#3075)
* Fixed shop changes

* Update option description

* Apply suggestions from Vi's review (thank you)

* Fix for plando connections on a full scene

* Plando connections should work better now for complicated paths

* Even more good plando connections yes

* Starting to move the info over

* Fixing up formatting a bit

* Remove unneeded item info

* Put in updated_reachable_regions, to replace add_dependent_regions

* Updated to match ladder shuffle

* More stuff I guess

* It functions!

* It mostly works with plando now, some slight issues still

* Fixed minor logic bug

* Fixed world leakage

* Change exception message

* Make exception message better for troubleshooting failed connections

* Merged with main

* technically a logic fix but it would never matter cause no start shuffle

* Add a couple more alias item groups cause yeah

* Rename beneath the vault front -> beneath the vault main

* Flip lantern access rule to the region

* Add missing connection to traversal reqs

* Move start_inventory_from_pool to the top so that it's next to start_inventory

* Reword the fixed shop description slightly

* Refactor per ixrec's comments

* Greatly reduced an overcomplicated block because Vi is cool and smart and also cool

* Rewrite traversal reqs thing per Vi's comments
2024-05-20 01:01:24 +02:00
Star Rauchenberger
12cde88f95 Lingo: Fixed edge case sunwarp shuffle accessibility issue (#3228)
* Lingo: Fixed edge case sunwarp shuffle accessibility issue

* Minor readability update

---------

Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
2024-05-20 00:56:24 +02:00
Alchav
e0b6889634 ALTTP: Second attempt to fix Swamp Palace boss logic (#3315) 2024-05-19 22:18:41 +02:00
black-sliver
14321d6ba2 Factorio: update factorio-rcon (#3198)
2.1.1 didn't work with py3.8, 2.1.2 fixes that
2024-05-19 20:41:18 +02:00
black-sliver
e978109410 WebHost: properly stop worker threads (#3340)
* WebHost: properly stop worker threads

* Less jank

* Forgot the try-catch around the while true
2024-05-19 20:40:36 +02:00
black-sliver
019dfb8242 CustomServer: re-add missing Archipelago to data package (#3341) 2024-05-19 20:40:08 +02:00
Doug Hoskisson
8e9a050889 Zillion: "item counts" OptionGroup (#3338) 2024-05-19 14:36:47 -04:00
Fabian Dill
2801e21296 WebHost: fixup WebHostLib/options.py (#3332)
* WebHost: fixup WebHostLib/options.py

* Update WebHostLib/options.py

* Update WebHostLib/options.py

* fix visibility flag handling
2024-05-19 14:21:46 -04:00
Fabian Dill
e97eddcdaf WebHost: move atexit saving to end of room hosting function (#3339) 2024-05-19 18:25:56 +02:00
Fabian Dill
d3f4ee4994 WebHost: re-introduce per-Room Locker (#3337) 2024-05-19 16:31:35 +02:00
black-sliver
cf34f125d6 CustomServer: don't mutate static server data (#3334)
when switching to multiple rooms per process, we ended up modifying the static server data
because that's how _load works and the data is now shared between multiple rooms.
2024-05-19 15:32:11 +02:00
Fabian Dill
663b50b33e WebHost: fix AutoLauncher restarting rooms due to race condition (#3333) 2024-05-19 15:17:55 +02:00
2202 changed files with 476309 additions and 95078 deletions

210
.dockerignore Normal file
View File

@@ -0,0 +1,210 @@
.git
.github
.run
docs
test
typings
*Client.py
.idea
.vscode
*_Spoiler.txt
*.bmbp
*.apbp
*.apl2ac
*.apm3
*.apmc
*.apz5
*.aptloz
*.apemerald
*.pyc
*.pyd
*.sfc
*.z64
*.n64
*.nes
*.smc
*.sms
*.gb
*.gbc
*.gba
*.wixobj
*.lck
*.db3
*multidata
*multisave
*.archipelago
*.apsave
*.BIN
*.puml
setups
build
bundle/components.wxs
dist
/prof/
README.html
.vs/
EnemizerCLI/
/Players/
/SNI/
/sni-*/
/appimagetool*
/host.yaml
/options.yaml
/config.yaml
/logs/
_persistent_storage.yaml
mystery_result_*.yaml
*-errors.txt
success.txt
output/
Output Logs/
/factorio/
/Minecraft Forge Server/
/WebHostLib/static/generated
/freeze_requirements.txt
/Archipelago.zip
/setup.ini
/installdelete.iss
/data/user.kv
/datapackage
/custom_worlds
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
*.dll
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
installer.log
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# vim editor
*.swp
# SageMath parsed files
*.sage.py
# Environments
.env
.venv*
env/
venv/
/venv*/
ENV/
env.bak/
venv.bak/
*.code-workspace
shell.nix
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# Cython intermediates
_speedups.c
_speedups.cpp
_speedups.html
# minecraft server stuff
jdk*/
minecraft*/
minecraft_versions.json
!worlds/minecraft/
# pyenv
.python-version
#undertale stuff
/Undertale/
# OS General Files
.DS_Store
.AppleDouble
.LSOverride
Thumbs.db
[Dd]esktop.ini

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

1
.github/labeler.yml vendored
View File

@@ -21,7 +21,6 @@
- '!data/**'
- '!.run/**'
- '!.github/**'
- '!worlds_disabled/**'
- '!worlds/**'
- '!WebHost.py'
- '!WebHostLib/**'

View File

@@ -1,8 +1,25 @@
{
"include": [
"type_check.py",
"../BizHawkClient.py",
"../Patch.py",
"../rule_builder/cached_world.py",
"../rule_builder/options.py",
"../rule_builder/rules.py",
"../test/param.py",
"../test/general/test_groups.py",
"../test/general/test_helpers.py",
"../test/general/test_memory.py",
"../test/general/test_names.py",
"../test/general/test_rule_builder.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 +33,7 @@
"reportMissingImports": true,
"reportMissingTypeStubs": true,
"pythonVersion": "3.8",
"pythonVersion": "3.11",
"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.11'
- name: "Install dependencies"
if: env.diff != ''
@@ -65,7 +65,7 @@ jobs:
continue-on-error: false
if: env.diff != '' && matrix.task == 'flake8'
run: |
flake8 --count --select=E9,F63,F7,F82 --show-source --statistics ${{ env.diff }}
flake8 --count --select=E9,F63,F7,F82 --ignore F824 --show-source --statistics ${{ env.diff }}
- name: "flake8: Lint modified files"
continue-on-error: true

View File

@@ -1,4 +1,5 @@
# This workflow will build a release-like distribution when manually dispatched
# This workflow will build a release-like distribution when manually dispatched:
# a Windows x64 7zip, a Windows x64 Installer, a Linux AppImage and a Linux binary .tar.gz.
name: Build
@@ -9,37 +10,56 @@ on:
- 'setup.py'
- 'requirements.txt'
- '*.iss'
- 'worlds/*/archipelago.json'
pull_request:
paths:
- '.github/workflows/build.yml'
- 'setup.py'
- 'requirements.txt'
- '*.iss'
- 'worlds/*/archipelago.json'
workflow_dispatch:
env:
ENEMIZER_VERSION: 7.1
APPIMAGETOOL_VERSION: 13
# NOTE: since appimage/appimagetool and appimage/type2-runtime does not have tags anymore,
# we check the sha256 and require manual intervention if it was updated.
APPIMAGE_FORK: 'PopTracker'
APPIMAGETOOL_VERSION: 'r-2025-11-18'
APPIMAGETOOL_X86_64_HASH: '4577a452b30af2337123fbb383aea154b618e51ad5448c3b62085cbbbfbfd9a2'
APPIMAGE_RUNTIME_VERSION: 'r-2025-11-07'
APPIMAGE_RUNTIME_X86_64_HASH: '27ddd3f78e483fc5f7856e413d7c17092917f8c35bfe3318a0d378aa9435ad17'
permissions: # permissions required for attestation
id-token: 'write'
attestations: 'write'
jobs:
# build-release-macos: # LF volunteer
build-win-py38: # RCs will still be built and signed by hand
build-win: # RCs and releases may still be built and signed by hand
runs-on: windows-latest
steps:
# - copy code below to release.yml -
- 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 +69,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,15 +79,54 @@ jobs:
$contents = Get-ChildItem -Path setups/*.exe -Force -Recurse
$SETUP_NAME=$contents[0].Name
echo "SETUP_NAME=$SETUP_NAME" >> $Env:GITHUB_ENV
# - copy code above to release.yml -
- name: Attest Build
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: actions/attest-build-provenance@v2
with:
subject-path: |
build/exe.*/ArchipelagoLauncher.exe
build/exe.*/ArchipelagoLauncherDebug.exe
build/exe.*/ArchipelagoGenerate.exe
build/exe.*/ArchipelagoServer.exe
dist/${{ env.ZIP_NAME }}
setups/${{ env.SETUP_NAME }}
- 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/VVVVVV.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:
runs-on: ubuntu-20.04
build-ubuntu2204:
runs-on: ubuntu-22.04
steps:
# - copy code below to release.yml -
- uses: actions/checkout@v4
@@ -85,14 +138,18 @@ 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
wget -nv https://github.com/AppImage/AppImageKit/releases/download/$APPIMAGETOOL_VERSION/appimagetool-x86_64.AppImage
echo "PYTHON=python3.12" >> $GITHUB_ENV
wget -nv https://github.com/$APPIMAGE_FORK/appimagetool/releases/download/$APPIMAGETOOL_VERSION/appimagetool-x86_64.AppImage
echo "$APPIMAGETOOL_X86_64_HASH appimagetool-x86_64.AppImage" | sha256sum -c
wget -nv https://github.com/$APPIMAGE_FORK/type2-runtime/releases/download/$APPIMAGE_RUNTIME_VERSION/runtime-x86_64
echo "$APPIMAGE_RUNTIME_X86_64_HASH runtime-x86_64" | sha256sum -c
chmod a+rx appimagetool-x86_64.AppImage
./appimagetool-x86_64.AppImage --appimage-extract
echo -e '#/bin/sh\n./squashfs-root/AppRun "$@"' > appimagetool
echo -e '#/bin/sh\n./squashfs-root/AppRun --runtime-file runtime-x86_64 "$@"' > appimagetool
chmod a+rx appimagetool
- name: Download run-time dependencies
run: |
@@ -104,29 +161,60 @@ jobs:
# charset-normalizer was somehow incomplete in the github runner
"${{ env.PYTHON }}" -m venv venv
source venv/bin/activate
"${{ env.PYTHON }}" -m pip install --upgrade pip PyGObject charset-normalizer
"${{ env.PYTHON }}" -m pip install --upgrade pip "PyGObject<3.51.0" charset-normalizer
python setup.py build_exe --yes bdist_appimage --yes
echo -e "setup.py build output:\n `ls build`"
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 -
- name: Attest Build
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: actions/attest-build-provenance@v2
with:
subject-path: |
build/exe.*/ArchipelagoLauncher
build/exe.*/ArchipelagoGenerate
build/exe.*/ArchipelagoServer
dist/${{ env.APPIMAGE_NAME }}*
dist/${{ env.TAR_NAME }}
- name: Build Again
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/VVVVVV.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.txt'
- '.github/workflows/ctest.yml'
pull_request:
paths:
- '**.cc?'
- '**.cpp'
- '**.cxx'
- '**.hh?'
- '**.hpp'
- '**.hxx'
- '**/CMakeLists.txt'
- '.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@0b201ec74fa43914dc39ae48a89fd1d8cb592756
if: startsWith(matrix.os,'windows')
- uses: Bacondish2023/setup-googletest@49065d1f7a6d21f6134864dd65980fe5dbe06c73
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

53
.github/workflows/docker.yml vendored Normal file
View File

@@ -0,0 +1,53 @@
name: Build and Publish Docker Images
on:
push:
paths:
- "**"
- "!docs/**"
- "!deploy/**"
- "!setup.py"
- "!.gitignore"
- "!.github/workflows/**"
- ".github/workflows/docker.yml"
branches:
- "dock-dev"
tags:
- "v?[0-9]+.[0-9]+.[0-9]*"
workflow_dispatch:
jobs:
push_to_registry:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
attestations: write
id-token: write
steps:
- name: Check out the repo
uses: actions/checkout@v5
- name: Log in to Docker Hub
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ubufugu/dockipelago
- name: Build and push Docker image
id: push
uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@@ -6,11 +6,12 @@ on:
permissions:
contents: read
pull-requests: write
env:
GH_REPO: ${{ github.repository }}
jobs:
labeler:
name: 'Apply content-based labels'
if: github.event.action == 'opened' || github.event.action == 'reopened' || github.event.action == 'synchronize'
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v5

View File

@@ -5,11 +5,22 @@ name: Release
on:
push:
tags:
- '*.*.*'
- 'v?[0-9]+.[0-9]+.[0-9]*'
env:
ENEMIZER_VERSION: 7.1
APPIMAGETOOL_VERSION: 13
# NOTE: since appimage/appimagetool and appimage/type2-runtime does not have tags anymore,
# we check the sha256 and require manual intervention if it was updated.
APPIMAGE_FORK: 'PopTracker'
APPIMAGETOOL_VERSION: 'r-2025-11-18'
APPIMAGETOOL_X86_64_HASH: '4577a452b30af2337123fbb383aea154b618e51ad5448c3b62085cbbbfbfd9a2'
APPIMAGE_RUNTIME_VERSION: 'r-2025-11-07'
APPIMAGE_RUNTIME_X86_64_HASH: '27ddd3f78e483fc5f7856e413d7c17092917f8c35bfe3318a0d378aa9435ad17'
permissions: # permissions required for attestation
id-token: 'write'
attestations: 'write'
contents: 'write' # additionally required for release
jobs:
create-release:
@@ -26,11 +37,79 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# build-release-windows: # this is done by hand because of signing
# build-release-macos: # LF volunteer
build-release-ubuntu2004:
runs-on: ubuntu-20.04
build-release-win:
runs-on: windows-latest
if: ${{ true }} # change to false to skip if release is built by hand
needs: create-release
steps:
- name: Set env
shell: bash
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
# - code below copied from build.yml -
- uses: actions/checkout@v4
- name: Install python
uses: actions/setup-python@v5
with:
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"
echo "ZIP_NAME=$ZIP_NAME" >> $Env:GITHUB_ENV
New-Item -Path dist -ItemType Directory -Force
cd build
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: Build Setup
run: |
& "${env:ProgramFiles(x86)}\Inno Setup 6\iscc.exe" inno_setup.iss /DNO_SIGNTOOL
if ( $? -eq $false ) {
Write-Error "Building setup failed!"
exit 1
}
$contents = Get-ChildItem -Path setups/*.exe -Force -Recurse
$SETUP_NAME=$contents[0].Name
echo "SETUP_NAME=$SETUP_NAME" >> $Env:GITHUB_ENV
# - code above copied from build.yml -
- name: Attest Build
uses: actions/attest-build-provenance@v2
with:
subject-path: |
build/exe.*/ArchipelagoLauncher.exe
build/exe.*/ArchipelagoLauncherDebug.exe
build/exe.*/ArchipelagoGenerate.exe
build/exe.*/ArchipelagoServer.exe
setups/*
- name: Add to Release
uses: softprops/action-gh-release@975c1b265e11dd76618af1c374e7981f9a6ff44a
with:
draft: true # see above
prerelease: false
name: Archipelago ${{ env.RELEASE_VERSION }}
files: |
setups/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build-release-ubuntu2204:
runs-on: ubuntu-22.04
needs: create-release
steps:
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
@@ -44,14 +123,18 @@ 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
wget -nv https://github.com/AppImage/AppImageKit/releases/download/$APPIMAGETOOL_VERSION/appimagetool-x86_64.AppImage
echo "PYTHON=python3.12" >> $GITHUB_ENV
wget -nv https://github.com/$APPIMAGE_FORK/appimagetool/releases/download/$APPIMAGETOOL_VERSION/appimagetool-x86_64.AppImage
echo "$APPIMAGETOOL_X86_64_HASH appimagetool-x86_64.AppImage" | sha256sum -c
wget -nv https://github.com/$APPIMAGE_FORK/type2-runtime/releases/download/$APPIMAGE_RUNTIME_VERSION/runtime-x86_64
echo "$APPIMAGE_RUNTIME_X86_64_HASH runtime-x86_64" | sha256sum -c
chmod a+rx appimagetool-x86_64.AppImage
./appimagetool-x86_64.AppImage --appimage-extract
echo -e '#/bin/sh\n./squashfs-root/AppRun "$@"' > appimagetool
echo -e '#/bin/sh\n./squashfs-root/AppRun --runtime-file runtime-x86_64 "$@"' > appimagetool
chmod a+rx appimagetool
- name: Download run-time dependencies
run: |
@@ -63,16 +146,24 @@ jobs:
# charset-normalizer was somehow incomplete in the github runner
"${{ env.PYTHON }}" -m venv venv
source venv/bin/activate
"${{ env.PYTHON }}" -m pip install --upgrade pip PyGObject charset-normalizer
"${{ env.PYTHON }}" -m pip install --upgrade pip "PyGObject<3.51.0" charset-normalizer
python setup.py build_exe --yes bdist_appimage --yes
echo -e "setup.py build output:\n `ls build`"
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 -
- name: Attest Build
uses: actions/attest-build-provenance@v2
with:
subject-path: |
build/exe.*/ArchipelagoLauncher
build/exe.*/ArchipelagoGenerate
build/exe.*/ArchipelagoServer
dist/*
- name: Add to Release
uses: softprops/action-gh-release@975c1b265e11dd76618af1c374e7981f9a6ff44a
with:

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

@@ -8,23 +8,29 @@ on:
paths:
- '**'
- '!docs/**'
- '!deploy/**'
- '!setup.py'
- '!Dockerfile'
- '!*.iss'
- '!.gitignore'
- '!.dockerignore'
- '!.github/workflows/**'
- '.github/workflows/unittests.yml'
pull_request:
paths:
- '**'
- '!docs/**'
- '!deploy/**'
- '!setup.py'
- '!Dockerfile'
- '!*.iss'
- '!.gitignore'
- '!.dockerignore'
- '!.github/workflows/**'
- '.github/workflows/unittests.yml'
jobs:
build:
unit:
runs-on: ${{ matrix.os }}
name: Test Python ${{ matrix.python.version }} ${{ matrix.os }}
@@ -33,16 +39,15 @@ jobs:
matrix:
os: [ubuntu-latest]
python:
- {version: '3.8'}
- {version: '3.9'}
- {version: '3.10'}
- {version: '3.11'}
- {version: '3.11.2'} # Change to '3.11' around 2026-06-10
- {version: '3.12'}
- {version: '3.13'}
include:
- python: {version: '3.8'} # win7 compat
- python: {version: '3.11'} # old compat
os: windows-latest
- python: {version: '3.11'} # current
- python: {version: '3.13'} # current
os: windows-latest
- python: {version: '3.11'} # current
- python: {version: '3.13'} # current
os: macos-latest
steps:
@@ -54,9 +59,38 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pytest-subtests pytest-xdist
pip install -r ci-requirements.txt
python ModuleUpdate.py --yes --force --append "WebHostLib/requirements.txt"
python Launcher.py --update_settings # make sure host.yaml exists for tests
- name: Unittests
run: |
pytest -n auto
hosting:
runs-on: ${{ matrix.os }}
name: Test hosting with ${{ matrix.python.version }} on ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
python:
- {version: '3.13'} # current
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python.version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python.version }}
- name: Install dependencies
run: |
python -m venv venv
source venv/bin/activate
python -m pip install --upgrade pip
python ModuleUpdate.py --yes --force --append "WebHostLib/requirements.txt"
- name: Test hosting
run: |
source venv/bin/activate
export PYTHONPATH=$(pwd)
timeout 600 python test/hosting/__main__.py

16
.gitignore vendored
View File

@@ -4,11 +4,13 @@
*_Spoiler.txt
*.bmbp
*.apbp
*.apcivvi
*.apl2ac
*.apm3
*.apmc
*.apz5
*.aptloz
*.aptww
*.apemerald
*.pyc
*.pyd
@@ -54,7 +56,6 @@ success.txt
output/
Output Logs/
/factorio/
/Minecraft Forge Server/
/WebHostLib/static/generated
/freeze_requirements.txt
/Archipelago.zip
@@ -62,6 +63,10 @@ Output Logs/
/installdelete.iss
/data/user.kv
/datapackage
/datapackage_export.json
/custom_worlds
# stubgen output
/out/
# Byte-compiled / optimized / DLL files
__pycache__/
@@ -149,7 +154,7 @@ venv/
ENV/
env.bak/
venv.bak/
.code-workspace
*.code-workspace
shell.nix
# Spyder project settings
@@ -177,15 +182,10 @@ dmypy.json
cython_debug/
# Cython intermediates
_speedups.c
_speedups.cpp
_speedups.html
# minecraft server stuff
jdk*/
minecraft*/
minecraft_versions.json
!worlds/minecraft/
# pyenv
.python-version

View File

@@ -0,0 +1,24 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Build APWorlds" type="PythonConfigurationType" factoryName="Python">
<module name="Archipelago" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/Launcher.py" />
<option name="PARAMETERS" value="&quot;Build APWorlds&quot;" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
</component>

9
AHITClient.py Normal file
View File

@@ -0,0 +1,9 @@
import sys
from worlds.ahit.Client import launch
import Utils
import ModuleUpdate
ModuleUpdate.update()
if __name__ == "__main__":
Utils.init_logging("AHITClient", exception_logger="Client")
launch(*sys.argv[1:])

View File

@@ -11,6 +11,7 @@ from typing import List
import Utils
from settings import get_settings
from NetUtils import ClientStatus
from Utils import async_start
from CommonClient import CommonContext, server_loop, gui_enabled, ClientCommandProcessor, logger, \
@@ -80,8 +81,8 @@ class AdventureContext(CommonContext):
self.local_item_locations = {}
self.dragon_speed_info = {}
options = Utils.get_options()
self.display_msgs = options["adventure_options"]["display_msgs"]
options = get_settings().adventure_options
self.display_msgs = options.display_msgs
async def server_auth(self, password_requested: bool = False):
if password_requested and not self.password:
@@ -102,7 +103,7 @@ class AdventureContext(CommonContext):
def on_package(self, cmd: str, args: dict):
if cmd == 'Connected':
self.locations_array = None
if Utils.get_options()["adventure_options"].get("death_link", False):
if get_settings().adventure_options.as_dict().get("death_link", False):
self.set_deathlink = True
async_start(self.get_freeincarnates_used())
elif cmd == "RoomInfo":
@@ -112,7 +113,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[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"]:
@@ -406,6 +407,7 @@ async def atari_sync_task(ctx: AdventureContext):
except ConnectionRefusedError:
logger.debug("Connection Refused, Trying Again")
ctx.atari_status = CONNECTION_REFUSED_STATUS
await asyncio.sleep(1)
continue
except CancelledError:
pass
@@ -415,8 +417,9 @@ async def atari_sync_task(ctx: AdventureContext):
async def run_game(romfile):
auto_start = Utils.get_options()["adventure_options"].get("rom_start", True)
rom_args = Utils.get_options()["adventure_options"].get("rom_args")
options = get_settings().adventure_options
auto_start = options.rom_start
rom_args = options.rom_args
if auto_start is True:
import webbrowser
webbrowser.open(romfile)
@@ -511,7 +514,7 @@ if __name__ == '__main__':
import colorama
colorama.init()
colorama.just_fix_windows_console()
asyncio.run(main())
colorama.deinit()

File diff suppressed because it is too large Load Diff

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:])

491
CommonClient.py Normal file → Executable file
View File

@@ -1,5 +1,6 @@
from __future__ import annotations
import collections
import copy
import logging
import asyncio
@@ -8,6 +9,7 @@ import sys
import typing
import time
import functools
import warnings
import ModuleUpdate
ModuleUpdate.update()
@@ -19,22 +21,20 @@ import Utils
if __name__ == "__main__":
Utils.init_logging("TextClient", exception_logger="Client")
from MultiServer import CommandProcessor
from MultiServer import CommandProcessor, mark_raw
from NetUtils import (Endpoint, decode, NetworkItem, encode, JSONtoTextParser, ClientStatus, Permission, NetworkSlot,
RawJSONtoTextParser, add_json_text, add_json_location, add_json_item, JSONTypes)
from Utils import Version, stream_input, async_start
RawJSONtoTextParser, add_json_text, add_json_location, add_json_item, JSONTypes, HintStatus, SlotType)
from Utils import gui_enabled, Version, stream_input, async_start
from worlds import network_data_package, AutoWorldRegister
import os
import ssl
if typing.TYPE_CHECKING:
import kvui
import argparse
logger = logging.getLogger("Client")
# without terminal, we have to use gui mode
gui_enabled = not sys.stdout or "--nogui" not in sys.argv
@Utils.cache_argsless
def get_ssl_context():
@@ -43,14 +43,27 @@ 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:
"""Close connections and client"""
if self.ctx.ui:
self.ctx.ui.stop()
self.ctx.exit_event.set()
return True
@@ -59,6 +72,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
@@ -92,7 +106,9 @@ class ClientCommandProcessor(CommandProcessor):
return False
count = 0
checked_count = 0
for location, location_id in AutoWorldRegister.world_types[self.ctx.game].location_name_to_id.items():
lookup = self.ctx.location_names[self.ctx.game]
for location_id, location in lookup.items():
if filter_text and filter_text not in location:
continue
if location_id < 0:
@@ -113,43 +129,87 @@ class ClientCommandProcessor(CommandProcessor):
self.output("No missing location checks found.")
return True
def _cmd_items(self):
def output_datapackage_part(self, name: typing.Literal["Item Names", "Location Names"]) -> bool:
"""
Helper to digest a specific section of this game's datapackage.
:param name: Printed to the user as context for the part.
:return: Whether the process was successful.
"""
if not self.ctx.game:
self.output(f"No game set, cannot determine {name}.")
return False
lookup = self.ctx.item_names if name == "Item Names" else self.ctx.location_names
lookup = lookup[self.ctx.game]
self.output(f"{name} for {self.ctx.game}")
for name in lookup.values():
self.output(name)
return True
def _cmd_items(self) -> bool:
"""List all item names for the currently running game."""
if not self.ctx.game:
self.output("No game set, cannot determine existing items.")
return False
self.output(f"Item Names for {self.ctx.game}")
for item_name in AutoWorldRegister.world_types[self.ctx.game].item_name_to_id:
self.output(item_name)
return self.output_datapackage_part("Item Names")
def _cmd_item_groups(self):
"""List all item group names for the currently running game."""
if not self.ctx.game:
self.output("No game set, cannot determine existing item groups.")
return False
self.output(f"Item Group Names for {self.ctx.game}")
for group_name in AutoWorldRegister.world_types[self.ctx.game].item_name_groups:
self.output(group_name)
def _cmd_locations(self):
def _cmd_locations(self) -> bool:
"""List all location names for the currently running game."""
if not self.ctx.game:
self.output("No game set, cannot determine existing locations.")
return False
self.output(f"Location Names for {self.ctx.game}")
for location_name in AutoWorldRegister.world_types[self.ctx.game].location_name_to_id:
self.output(location_name)
return self.output_datapackage_part("Location Names")
def _cmd_location_groups(self):
"""List all location group names for the currently running game."""
if not self.ctx.game:
self.output("No game set, cannot determine existing location groups.")
return False
self.output(f"Location Group Names for {self.ctx.game}")
for group_name in AutoWorldRegister.world_types[self.ctx.game].location_name_groups:
self.output(group_name)
def output_group_part(self, group_key: typing.Literal["item_name_groups", "location_name_groups"],
filter_key: str,
name: str) -> bool:
"""
Logs an item or location group from the player's game's datapackage.
def _cmd_ready(self):
:param group_key: Either Item or Location group to be processed.
:param filter_key: Which group key to filter to. If an empty string is passed will log all item/location groups.
:param name: Printed to the user as context for the part.
:return: Whether the process was successful.
"""
if not self.ctx.game:
self.output(f"No game set, cannot determine existing {name} Groups.")
return False
lookup = Utils.persistent_load().get("groups_by_checksum", {}).get(self.ctx.checksums[self.ctx.game], {})\
.get(self.ctx.game, {}).get(group_key, {})
if lookup is None:
self.output("datapackage not yet loaded, try again")
return False
if filter_key:
if filter_key not in lookup:
self.output(f"Unknown {name} Group {filter_key}")
return False
self.output(f"{name}s for {name} Group \"{filter_key}\"")
for entry in lookup[filter_key]:
self.output(entry)
else:
self.output(f"{name} Groups for {self.ctx.game}")
for group in lookup:
self.output(group)
return True
@mark_raw
def _cmd_item_groups(self, key: str = "") -> bool:
"""
List all item group names for the currently running game.
:param key: Which item group to filter to. Will log all groups if empty.
"""
return self.output_group_part("item_name_groups", key, "Item")
@mark_raw
def _cmd_location_groups(self, key: str = "") -> bool:
"""
List all location group names for the currently running game.
:param key: Which item group to filter to. Will log all groups if empty.
"""
return self.output_group_part("location_name_groups", key, "Location")
def _cmd_ready(self) -> bool:
"""Send ready status to server."""
self.ctx.ready = not self.ctx.ready
if self.ctx.ready:
@@ -159,30 +219,85 @@ class ClientCommandProcessor(CommandProcessor):
state = ClientStatus.CLIENT_CONNECTED
self.output("Unreadied.")
async_start(self.ctx.send_msgs([{"cmd": "StatusUpdate", "status": state}]), name="send StatusUpdate")
return True
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
want_slot_data: bool = True # should slot_data be retrieved via Connect
# data package
# Contents in flux until connection to server is made, to download correct data for this multiworld.
item_names: typing.Dict[int, str] = Utils.KeyedDefaultDict(lambda code: f'Unknown item (ID:{code})')
location_names: typing.Dict[int, str] = Utils.KeyedDefaultDict(lambda code: f'Unknown location (ID:{code})')
class NameLookupDict:
"""A specialized dict, with helper methods, for id -> name item/location data package lookups by game."""
def __init__(self, ctx: CommonContext, lookup_type: typing.Literal["item", "location"]):
self.ctx: CommonContext = ctx
self.lookup_type: typing.Literal["item", "location"] = lookup_type
self._unknown_item: typing.Callable[[int], str] = lambda key: f"Unknown {lookup_type} (ID: {key})"
self._archipelago_lookup: typing.Dict[int, str] = {}
self._game_store: typing.Dict[str, typing.ChainMap[int, str]] = collections.defaultdict(
lambda: collections.ChainMap(self._archipelago_lookup, Utils.KeyedDefaultDict(self._unknown_item)))
# noinspection PyTypeChecker
def __getitem__(self, key: str) -> typing.Mapping[int, str]:
assert isinstance(key, str), f"ctx.{self.lookup_type}_names used with an id, use the lookup_in_ helpers instead"
return self._game_store[key]
def __len__(self) -> int:
return len(self._game_store)
def __iter__(self) -> typing.Iterator[str]:
return iter(self._game_store)
def __repr__(self) -> str:
return repr(self._game_store)
def lookup_in_game(self, code: int, game_name: typing.Optional[str] = None) -> str:
"""Returns the name for an item/location id in the context of a specific game or own game if `game` is
omitted.
"""
if game_name is None:
game_name = self.ctx.game
assert game_name is not None, f"Attempted to lookup {self.lookup_type} with no game name available."
return self._game_store[game_name][code]
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
assert slot is not None, f"Attempted to lookup {self.lookup_type} with no slot info available."
return self.lookup_in_game(code, self.ctx.slot_info[slot].game)
def update_game(self, game: str, name_to_id_lookup_table: typing.Dict[str, int]) -> None:
"""Overrides existing lookup tables for a particular game."""
id_to_name_lookup_table = Utils.KeyedDefaultDict(self._unknown_item)
id_to_name_lookup_table.update({code: name for name, code in name_to_id_lookup_table.items()})
self._game_store[game] = collections.ChainMap(self._archipelago_lookup, id_to_name_lookup_table)
if game == "Archipelago":
# Keep track of the Archipelago data package separately so if it gets updated in a custom datapackage,
# it updates in all chain maps automatically.
self._archipelago_lookup.clear()
self._archipelago_lookup.update(id_to_name_lookup_table)
# defaults
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
@@ -198,40 +313,73 @@ class CommonContext:
last_death_link: float = time.time() # last send/received death link on AP layer
# remaining type info
slot_info: typing.Dict[int, NetworkSlot]
server_address: typing.Optional[str]
password: typing.Optional[str]
hint_cost: typing.Optional[int]
hint_points: typing.Optional[int]
player_names: typing.Dict[int, str]
slot_info: dict[int, NetworkSlot]
"""Slot Info from the server for the current connection"""
server_address: str | None
"""Autoconnect address provided by the ctx constructor"""
password: str | None
"""Password used for Connecting, expected by server_auth"""
hint_cost: int | None
"""Current Hint Cost per Hint from the server"""
hint_points: int | None
"""Current available Hint Points from the server"""
player_names: dict[int, str]
"""Current lookup of slot number to player display name from server (includes aliases)"""
finished_game: bool
"""
Bool to signal that status should be updated to Goal after reconnecting
to be used to ensure that a StatusUpdate packet does not get lost when disconnected
"""
ready: bool
team: typing.Optional[int]
slot: typing.Optional[int]
auth: typing.Optional[str]
seed_name: typing.Optional[str]
"""Bool to keep track of state for the /ready command"""
team: int | None
"""Team number of currently connected slot"""
slot: int | None
"""Slot number of currently connected slot"""
auth: str | None
"""Name used in Connect packet"""
seed_name: str | None
"""Seed name that will be validated on opening a socket if present"""
# locations
locations_checked: typing.Set[int] # local state
locations_scouted: typing.Set[int]
items_received: typing.List[NetworkItem]
missing_locations: typing.Set[int] # server state
checked_locations: typing.Set[int] # server state
server_locations: typing.Set[int] # all locations the server knows of, missing_location | checked_locations
locations_info: typing.Dict[int, NetworkItem]
locations_checked: set[int]
"""
Local container of location ids checked to signal that LocationChecks should be resent after reconnecting
to be used to ensure that a LocationChecks packet does not get lost when disconnected
"""
locations_scouted: set[int]
"""
Local container of location ids scouted to signal that LocationScouts should be resent after reconnecting
to be used to ensure that a LocationScouts packet does not get lost when disconnected
"""
items_received: list[NetworkItem]
"""List of NetworkItems recieved from the server"""
missing_locations: set[int]
"""Container of Locations that are unchecked per server state"""
checked_locations: set[int]
"""Container of Locations that are checked per server state"""
server_locations: set[int]
"""Container of Locations that exist per server state; a combination between missing and checked locations"""
locations_info: dict[int, NetworkItem]
"""Dict of location id: NetworkItem info from LocationScouts request"""
# data storage
stored_data: typing.Dict[str, typing.Any]
stored_data_notification_keys: typing.Set[str]
stored_data: dict[str, typing.Any]
"""
Data Storage values by key that were retrieved from the server
any keys subscribed to with SetNotify will be kept up to date
"""
stored_data_notification_keys: set[str]
"""Current container of watched Data Storage keys, managed by ctx.set_notify"""
# internals
# current message box through kvui
_messagebox: typing.Optional["kvui.MessageBox"] = None
# message box reporting a loss of connection
"""Current message box through kvui"""
_messagebox_connection_loss: typing.Optional["kvui.MessageBox"] = None
"""Message box reporting a loss of connection"""
def __init__(self, server_address: typing.Optional[str], password: typing.Optional[str]) -> None:
def __init__(self, server_address: typing.Optional[str] = None, password: typing.Optional[str] = None) -> None:
# server state
self.server_address = server_address
self.username = None
@@ -271,8 +419,14 @@ class CommonContext:
self.exit_event = asyncio.Event()
self.watcher_event = asyncio.Event()
self.item_names = self.NameLookupDict(self, "item")
self.location_names = self.NameLookupDict(self, "location")
self.checksums = {}
self.jsontotextparser = JSONtoTextParser(self)
self.rawjsontotextparser = RawJSONtoTextParser(self)
if self.game:
self.checksums[self.game] = network_data_package["games"][self.game]["checksum"]
self.update_data_package(network_data_package)
# execution
@@ -325,6 +479,8 @@ class CommonContext:
await self.server.socket.close()
if self.server_task is not None:
await self.server_task
if self.ui:
self.ui.update_hints()
async def send_msgs(self, msgs: typing.List[typing.Any]) -> None:
""" `msgs` JSON serializable """
@@ -356,7 +512,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,
@@ -366,6 +525,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:
@@ -386,6 +553,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:
@@ -393,6 +561,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
@@ -402,6 +571,10 @@ class CommonContext:
return print_json_packet.get("type", "") == "ItemSend" \
and not self.slot_concerns_self(print_json_packet["receiving"]) \
and not self.slot_concerns_self(print_json_packet["item"].player)
def is_connection_change(self, print_json_packet: dict) -> bool:
"""Helper function for filtering out connection changes."""
return print_json_packet.get("type", "") in ["Join","Part"]
def on_print(self, args: dict):
logger.info(args["text"])
@@ -425,7 +598,13 @@ class CommonContext:
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)
@@ -437,6 +616,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()
@@ -451,10 +631,16 @@ 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],
remote_data_package_checksums: typing.Dict[str, str]):
"""Validate that all data is present for the current multiworld.
Download, assimilate and cache missing data from the server."""
@@ -463,52 +649,65 @@ class CommonContext:
needed_updates: typing.Set[str] = set()
for game in relevant_games:
if game not in remote_date_package_versions and game not in remote_data_package_checksums:
if game not in remote_data_package_checksums:
continue
remote_version: int = remote_date_package_versions.get(game, 0)
remote_checksum: typing.Optional[str] = remote_data_package_checksums.get(game)
if remote_version == 0 and not remote_checksum: # custom data package and no checksum for this game
if not remote_checksum: # custom data package and no checksum for this game
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_checksum: typing.Optional[str] = self.checksums.get(game)
# no action required if cached version is new enough
if remote_checksum != cached_checksum:
local_checksum: typing.Optional[str] = network_data_package["games"].get(game, {}).get("checksum")
if remote_checksum == local_checksum:
self.update_game(network_data_package["games"][game], game)
else:
self.update_game(cached_game)
cached_game = Utils.load_data_package_for_checksum(game, remote_checksum)
cache_checksum: typing.Optional[str] = cached_game.get("checksum")
# download remote version if cache is not new enough
if 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):
for item_name, item_id in game_package["item_name_to_id"].items():
self.item_names[item_id] = item_name
for location_name, location_id in game_package["location_name_to_id"].items():
self.location_names[location_id] = location_name
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.checksums[game] = game_package.get("checksum")
def update_data_package(self, data_package: dict):
for game, game_data in data_package["games"].items():
self.update_game(game_data)
self.update_game(game_data, game)
def consume_network_data_package(self, data_package: dict):
self.update_data_package(data_package)
current_cache = Utils.persistent_load().get("datapackage", {}).get("games", {})
current_cache.update(data_package["games"])
Utils.persistent_store("datapackage", "games", current_cache)
logger.info(f"Got new ID/Name DataPackage for {', '.join(data_package['games'])}")
for game, game_data in data_package["games"].items():
Utils.store_data_package_for_checksum(game, game_data)
def consume_network_item_groups(self):
data = {"item_name_groups": self.stored_data[f"_read_item_name_groups_{self.game}"]}
current_cache = Utils.persistent_load().get("groups_by_checksum", {}).get(self.checksums[self.game], {})
if self.game in current_cache:
current_cache[self.game].update(data)
else:
current_cache[self.game] = data
Utils.persistent_store("groups_by_checksum", self.checksums[self.game], current_cache)
def consume_network_location_groups(self):
data = {"location_name_groups": self.stored_data[f"_read_location_name_groups_{self.game}"]}
current_cache = Utils.persistent_load().get("groups_by_checksum", {}).get(self.checksums[self.game], {})
if self.game in current_cache:
current_cache[self.game].update(data)
else:
current_cache[self.game] = data
Utils.persistent_store("groups_by_checksum", self.checksums[self.game], current_cache)
# data storage
def set_notify(self, *keys: str) -> None:
@@ -536,6 +735,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()
@@ -549,6 +749,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")
@@ -558,7 +759,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"
@@ -585,21 +786,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.")
@@ -643,9 +859,9 @@ async def server_loop(ctx: CommonContext, address: typing.Optional[str] = None)
server_url = urllib.parse.urlparse(address)
if server_url.username:
ctx.username = server_url.username
ctx.username = urllib.parse.unquote(server_url.username)
if server_url.password:
ctx.password = server_url.password
ctx.password = urllib.parse.unquote(server_url.password)
def reconnect_hint() -> str:
return ", type /connect to reconnect" if ctx.server_address else ""
@@ -750,9 +966,8 @@ async def process_server_cmd(ctx: CommonContext, args: dict):
logger.info(' %s (Player %d)' % (network_player.alias, network_player.slot))
# update data package
data_package_versions = args.get("datapackage_versions", {})
data_package_checksums = args.get("datapackage_checksums", {})
await ctx.prepare_data_package(set(args["games"]), data_package_versions, data_package_checksums)
await ctx.prepare_data_package(set(args["games"]), data_package_checksums)
await ctx.server_auth(args['password'])
@@ -768,6 +983,7 @@ async def process_server_cmd(ctx: CommonContext, args: dict):
ctx.disconnected_intentionally = True
ctx.event_invalid_game()
elif 'IncompatibleVersion' in errors:
ctx.disconnected_intentionally = True
raise Exception('Server reported your client version as incompatible. '
'This probably means you have to update.')
elif 'InvalidItemsHandling' in errors:
@@ -787,10 +1003,17 @@ 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}")
if ctx.game:
game = ctx.game
else:
game = ctx.slot_info[ctx.slot][1]
ctx.stored_data_notification_keys.add(f"_read_item_name_groups_{game}")
ctx.stored_data_notification_keys.add(f"_read_location_name_groups_{game}")
msgs = []
if ctx.locations_checked:
msgs.append({"cmd": "LocationChecks",
@@ -871,11 +1094,19 @@ async def process_server_cmd(ctx: CommonContext, args: dict):
ctx.stored_data.update(args["keys"])
if ctx.ui and f"_read_hints_{ctx.team}_{ctx.slot}" in args["keys"]:
ctx.ui.update_hints()
if f"_read_item_name_groups_{ctx.game}" in args["keys"]:
ctx.consume_network_item_groups()
if f"_read_location_name_groups_{ctx.game}" in args["keys"]:
ctx.consume_network_location_groups()
elif cmd == "SetReply":
ctx.stored_data[args["key"]] = args["value"]
if ctx.ui and f"_read_hints_{ctx.team}_{ctx.slot}" == args["key"]:
ctx.ui.update_hints()
elif f"_read_item_name_groups_{ctx.game}" == args["key"]:
ctx.consume_network_item_groups()
elif f"_read_location_name_groups_{ctx.game}" == args["key"]:
ctx.consume_network_location_groups()
elif args["key"].startswith("EnergyLink"):
ctx.current_energy_link_value = args["value"]
if ctx.ui:
@@ -907,6 +1138,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.')
@@ -916,7 +1148,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"}
@@ -928,7 +1186,7 @@ def run_as_textclient():
if password_requested and not self.password:
await super(TextContext, self).server_auth(password_requested)
await self.get_username()
await self.send_connect()
await self.send_connect(game="")
def on_package(self, cmd: str, args: dict):
if cmd == "Connected":
@@ -955,17 +1213,12 @@ 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)
colorama.init()
# use colorama to display colored text highlighting on windows
colorama.just_fix_windows_console()
asyncio.run(main(args))
colorama.deinit()
@@ -973,4 +1226,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

100
Dockerfile Normal file
View File

@@ -0,0 +1,100 @@
# hadolint global ignore=SC1090,SC1091
# Source
FROM scratch AS release
WORKDIR /release
ADD https://github.com/Ijwu/Enemizer/releases/latest/download/ubuntu.16.04-x64.zip Enemizer.zip
# Enemizer
FROM alpine:3.21 AS enemizer
ARG TARGETARCH
WORKDIR /release
COPY --from=release /release/Enemizer.zip .
# No release for arm architecture. Skip.
RUN if [ "$TARGETARCH" = "amd64" ]; then \
apk add unzip=6.0-r15 --no-cache && \
unzip -u Enemizer.zip -d EnemizerCLI && \
chmod -R 777 EnemizerCLI; \
else touch EnemizerCLI; fi
# Cython builder stage
FROM python:3.12 AS cython-builder
WORKDIR /build
# Copy and install requirements first (better caching)
COPY requirements.txt WebHostLib/requirements.txt
RUN pip install --no-cache-dir -r \
WebHostLib/requirements.txt \
"setuptools>=75,<81"
COPY _speedups.pyx .
COPY intset.h .
RUN cythonize -b -i _speedups.pyx
# Archipelago
FROM python:3.12-slim-bookworm AS archipelago
ARG TARGETARCH
ENV VIRTUAL_ENV=/opt/venv
ENV PYTHONUNBUFFERED=1
WORKDIR /app
# Install requirements
# hadolint ignore=DL3008
RUN apt-get update && \
apt-get install -y --no-install-recommends \
git \
gcc=4:12.2.0-3 \
libc6-dev \
libtk8.6=8.6.13-2 \
g++=4:12.2.0-3 \
curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Create and activate venv
RUN python -m venv $VIRTUAL_ENV; \
. $VIRTUAL_ENV/bin/activate
# Copy and install requirements first (better caching)
COPY WebHostLib/requirements.txt WebHostLib/requirements.txt
RUN pip install --no-cache-dir -r \
WebHostLib/requirements.txt \
gunicorn==23.0.0
COPY . .
COPY --from=cython-builder /build/*.so ./
# Run ModuleUpdate
RUN python ModuleUpdate.py -y
# Purge unneeded packages
RUN apt-get purge -y \
git \
gcc \
libc6-dev \
g++ && \
apt-get autoremove -y
# Copy necessary components
COPY --from=enemizer /release/EnemizerCLI /tmp/EnemizerCLI
# No release for arm architecture. Skip.
RUN if [ "$TARGETARCH" = "amd64" ]; then \
cp -r /tmp/EnemizerCLI EnemizerCLI; \
fi; \
rm -rf /tmp/EnemizerCLI
# Define health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD curl -f http://localhost:${PORT:-80} || exit 1
# Ensure no runtime ModuleUpdate.
ENV SKIP_REQUIREMENTS_UPDATE=true
ENTRYPOINT [ "python", "WebHost.py" ]

View File

@@ -1,267 +0,0 @@
import asyncio
import copy
import json
import time
from asyncio import StreamReader, StreamWriter
from typing import List
import Utils
from Utils import async_start
from CommonClient import CommonContext, server_loop, gui_enabled, ClientCommandProcessor, logger, \
get_base_parser
SYSTEM_MESSAGE_ID = 0
CONNECTION_TIMING_OUT_STATUS = "Connection timing out. Please restart your emulator, then restart connector_ff1.lua"
CONNECTION_REFUSED_STATUS = "Connection Refused. Please start your emulator and make sure connector_ff1.lua is running"
CONNECTION_RESET_STATUS = "Connection was reset. Please restart your emulator, then restart connector_ff1.lua"
CONNECTION_TENTATIVE_STATUS = "Initial Connection Made"
CONNECTION_CONNECTED_STATUS = "Connected"
CONNECTION_INITIAL_STATUS = "Connection has not been initiated"
DISPLAY_MSGS = True
class FF1CommandProcessor(ClientCommandProcessor):
def __init__(self, ctx: CommonContext):
super().__init__(ctx)
def _cmd_nes(self):
"""Check NES Connection State"""
if isinstance(self.ctx, FF1Context):
logger.info(f"NES Status: {self.ctx.nes_status}")
def _cmd_toggle_msgs(self):
"""Toggle displaying messages in EmuHawk"""
global DISPLAY_MSGS
DISPLAY_MSGS = not DISPLAY_MSGS
logger.info(f"Messages are now {'enabled' if DISPLAY_MSGS else 'disabled'}")
class FF1Context(CommonContext):
command_processor = FF1CommandProcessor
game = 'Final Fantasy'
items_handling = 0b111 # full remote
def __init__(self, server_address, password):
super().__init__(server_address, password)
self.nes_streams: (StreamReader, StreamWriter) = None
self.nes_sync_task = None
self.messages = {}
self.locations_array = None
self.nes_status = CONNECTION_INITIAL_STATUS
self.awaiting_rom = False
self.display_msgs = True
async def server_auth(self, password_requested: bool = False):
if password_requested and not self.password:
await super(FF1Context, self).server_auth(password_requested)
if not self.auth:
self.awaiting_rom = True
logger.info('Awaiting connection to NES to get Player information')
return
await self.send_connect()
def _set_message(self, msg: str, msg_id: int):
if DISPLAY_MSGS:
self.messages[time.time(), msg_id] = msg
def on_package(self, cmd: str, args: dict):
if cmd == 'Connected':
async_start(parse_locations(self.locations_array, self, True))
elif cmd == 'Print':
msg = args['text']
if ': !' not in msg:
self._set_message(msg, SYSTEM_MESSAGE_ID)
def on_print_json(self, args: dict):
if self.ui:
self.ui.print_json(copy.deepcopy(args["data"]))
else:
text = self.jsontotextparser(copy.deepcopy(args["data"]))
logger.info(text)
relevant = args.get("type", None) in {"Hint", "ItemSend"}
if relevant:
item = args["item"]
# goes to this world
if self.slot_concerns_self(args["receiving"]):
relevant = True
# found in this world
elif self.slot_concerns_self(item.player):
relevant = True
# not related
else:
relevant = False
if relevant:
item = args["item"]
msg = self.raw_text_parser(copy.deepcopy(args["data"]))
self._set_message(msg, item.item)
def run_gui(self):
from kvui import GameManager
class FF1Manager(GameManager):
logging_pairs = [
("Client", "Archipelago")
]
base_title = "Archipelago Final Fantasy 1 Client"
self.ui = FF1Manager(self)
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
def get_payload(ctx: FF1Context):
current_time = time.time()
return json.dumps(
{
"items": [item.item for item in ctx.items_received],
"messages": {f'{key[0]}:{key[1]}': value for key, value in ctx.messages.items()
if key[0] > current_time - 10}
}
)
async def parse_locations(locations_array: List[int], ctx: FF1Context, force: bool):
if locations_array == ctx.locations_array and not force:
return
else:
# print("New values")
ctx.locations_array = locations_array
locations_checked = []
if len(locations_array) > 0xFE and locations_array[0xFE] & 0x02 != 0 and not ctx.finished_game:
await ctx.send_msgs([
{"cmd": "StatusUpdate",
"status": 30}
])
ctx.finished_game = True
for location in ctx.missing_locations:
# index will be - 0x100 or 0x200
index = location
if location < 0x200:
# Location is a chest
index -= 0x100
flag = 0x04
else:
# Location is an NPC
index -= 0x200
flag = 0x02
# print(f"Location: {ctx.location_names[location]}")
# print(f"Index: {str(hex(index))}")
# print(f"value: {locations_array[index] & flag != 0}")
if locations_array[index] & flag != 0:
locations_checked.append(location)
if locations_checked:
# print([ctx.location_names[location] for location in locations_checked])
await ctx.send_msgs([
{"cmd": "LocationChecks",
"locations": locations_checked}
])
async def nes_sync_task(ctx: FF1Context):
logger.info("Starting nes connector. Use /nes for status information")
while not ctx.exit_event.is_set():
error_status = None
if ctx.nes_streams:
(reader, writer) = ctx.nes_streams
msg = get_payload(ctx).encode()
writer.write(msg)
writer.write(b'\n')
try:
await asyncio.wait_for(writer.drain(), timeout=1.5)
try:
# Data will return a dict with up to two fields:
# 1. A keepalive response of the Players Name (always)
# 2. An array representing the memory values of the locations area (if in game)
data = await asyncio.wait_for(reader.readline(), timeout=5)
data_decoded = json.loads(data.decode())
# print(data_decoded)
if ctx.game is not None and 'locations' in data_decoded:
# Not just a keep alive ping, parse
async_start(parse_locations(data_decoded['locations'], ctx, False))
if not ctx.auth:
ctx.auth = ''.join([chr(i) for i in data_decoded['playerName'] if i != 0])
if ctx.auth == '':
logger.info("Invalid ROM detected. No player name built into the ROM. Please regenerate"
"the ROM using the same link but adding your slot name")
if ctx.awaiting_rom:
await ctx.server_auth(False)
except asyncio.TimeoutError:
logger.debug("Read Timed Out, Reconnecting")
error_status = CONNECTION_TIMING_OUT_STATUS
writer.close()
ctx.nes_streams = None
except ConnectionResetError as e:
logger.debug("Read failed due to Connection Lost, Reconnecting")
error_status = CONNECTION_RESET_STATUS
writer.close()
ctx.nes_streams = None
except TimeoutError:
logger.debug("Connection Timed Out, Reconnecting")
error_status = CONNECTION_TIMING_OUT_STATUS
writer.close()
ctx.nes_streams = None
except ConnectionResetError:
logger.debug("Connection Lost, Reconnecting")
error_status = CONNECTION_RESET_STATUS
writer.close()
ctx.nes_streams = None
if ctx.nes_status == CONNECTION_TENTATIVE_STATUS:
if not error_status:
logger.info("Successfully Connected to NES")
ctx.nes_status = CONNECTION_CONNECTED_STATUS
else:
ctx.nes_status = f"Was tentatively connected but error occured: {error_status}"
elif error_status:
ctx.nes_status = error_status
logger.info("Lost connection to nes and attempting to reconnect. Use /nes for status updates")
else:
try:
logger.debug("Attempting to connect to NES")
ctx.nes_streams = await asyncio.wait_for(asyncio.open_connection("localhost", 52980), timeout=10)
ctx.nes_status = CONNECTION_TENTATIVE_STATUS
except TimeoutError:
logger.debug("Connection Timed Out, Trying Again")
ctx.nes_status = CONNECTION_TIMING_OUT_STATUS
continue
except ConnectionRefusedError:
logger.debug("Connection Refused, Trying Again")
ctx.nes_status = CONNECTION_REFUSED_STATUS
continue
if __name__ == '__main__':
# Text Mode to use !hint and such with games that have no text entry
Utils.init_logging("FF1Client")
options = Utils.get_options()
DISPLAY_MSGS = options["ffr_options"]["display_msgs"]
async def main(args):
ctx = FF1Context(args.connect, args.password)
ctx.server_task = asyncio.create_task(server_loop(ctx), name="ServerLoop")
if gui_enabled:
ctx.run_gui()
ctx.run_cli()
ctx.nes_sync_task = asyncio.create_task(nes_sync_task(ctx), name="NES Sync")
await ctx.exit_event.wait()
ctx.server_address = None
await ctx.shutdown()
if ctx.nes_sync_task:
await ctx.nes_sync_task
import colorama
parser = get_base_parser()
args = parser.parse_args()
colorama.init()
asyncio.run(main(args))
colorama.deinit()

View File

@@ -1,12 +0,0 @@
from __future__ import annotations
import ModuleUpdate
ModuleUpdate.update()
from worlds.factorio.Client import check_stdin, launch
import Utils
if __name__ == "__main__":
Utils.init_logging("FactorioClient", exception_logger="Client")
check_stdin()
launch()

623
Fill.py
View File

@@ -4,7 +4,7 @@ import logging
import typing
from collections import Counter, deque
from BaseClasses import CollectionState, Item, Location, LocationProgressType, MultiWorld
from BaseClasses import CollectionState, Item, Location, LocationProgressType, MultiWorld, PlandoItemBlock
from Options import Accessibility
from worlds.AutoWorld import call_all
@@ -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,19 +29,20 @@ 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.
:param locations: Locations to be filled with item_pool
:param item_pool: Items to fill into the locations
:param locations: Locations to be filled with item_pool, gets mutated by removing locations that get filled.
:param item_pool: Items to fill into the locations, gets mutated by removing items that get placed.
:param single_player_placement: if true, can speed up placement if everything belongs to a single player
:param lock: locations are set to locked as they are filled
:param swap: if true, swaps of already place items are done in the event of a dead end
@@ -58,14 +64,24 @@ 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):
# The items added into `reachable_items` are placed starting from the end of each deque in
# `reachable_items`, so the items being placed are more likely to be found towards the end of `item_pool`.
for p, pool_item in enumerate(reversed(item_pool), start=1):
if pool_item is item:
item_pool.pop(p)
del item_pool[-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)
@@ -84,7 +100,7 @@ def fill_restrictive(multiworld: MultiWorld, base_state: CollectionState, locati
# if minimal accessibility, only check whether location is reachable if game not beatable
if multiworld.worlds[item_to_place.player].options.accessibility == Accessibility.option_minimal:
perform_access_check = not multiworld.has_beaten_game(maximum_exploration_state,
item_to_place.player) \
item_to_place.player) \
if single_player_placement else not has_beaten_game
else:
perform_access_check = True
@@ -100,12 +116,23 @@ def fill_restrictive(multiworld: MultiWorld, base_state: CollectionState, locati
else:
# we filled all reachable spots.
if swap:
# Keep a cache of previous safe swap states that might be usable to sweep from to produce the next
# swap state, instead of sweeping from `base_state` each time.
previous_safe_swap_state_cache: typing.Deque[CollectionState] = deque()
# Almost never are more than 2 states needed. The rare cases that do are usually highly restrictive
# single_player_placement=True pre-fills which can go through more than 10 states in some seeds.
max_swap_base_state_cache_length = 3
# try swapping this item with previously placed items in a safe way then in an unsafe way
swap_attempts = ((i, location, unsafe)
for unsafe in (False, True)
for i, location in enumerate(placements))
for (i, location, unsafe) in swap_attempts:
placed_item = location.item
if item_to_place == placed_item:
# The number of allowed swaps is limited, so do not allow a swap of an item with a copy of
# itself.
continue
# Unplaceable items can sometimes be swapped infinitely. Limit the
# number of times we will swap an individual item to prevent this
swap_count = swapped_items[placed_item.player, placed_item.name, unsafe]
@@ -114,40 +141,50 @@ def fill_restrictive(multiworld: MultiWorld, base_state: CollectionState, locati
location.item = None
placed_item.location = None
swap_state = sweep_from_pool(base_state, [placed_item, *item_pool] if unsafe else item_pool,
multiworld.get_filled_locations(item.player)
if single_player_placement else None)
for previous_safe_swap_state in previous_safe_swap_state_cache:
# If a state has already checked the location of the swap, then it cannot be used.
if location not in previous_safe_swap_state.advancements:
# Previous swap states will have collected all items in `item_pool`, so the new
# `swap_state` can skip having to collect them again.
# Previous swap states will also have already checked many locations, making the sweep
# faster.
swap_state = sweep_from_pool(previous_safe_swap_state, (placed_item,) if unsafe else (),
multiworld.get_filled_locations(item.player)
if single_player_placement else None)
break
else:
# No previous swap_state was usable as a base state to sweep from, so create a new one.
swap_state = sweep_from_pool(base_state, [placed_item, *item_pool] if unsafe else item_pool,
multiworld.get_filled_locations(item.player)
if single_player_placement else None)
# Unsafe states should not be added to the cache because they have collected `placed_item`.
if not unsafe:
if len(previous_safe_swap_state_cache) >= max_swap_base_state_cache_length:
# Remove the oldest cached state.
previous_safe_swap_state_cache.pop()
# Add the new state to the start of the cache.
previous_safe_swap_state_cache.appendleft(swap_state)
# unsafe means swap_state assumes we can somehow collect placed_item before item_to_place
# by continuing to swap, which is not guaranteed. This is unsafe because there is no mechanic
# to clean that up later, so there is a chance generation fails.
if (not single_player_placement or location.player == item_to_place.player) \
and location.can_fill(swap_state, item_to_place, perform_access_check):
# Add this item to the existing placement, and
# add the old item to the back of the queue
spot_to_fill = placements.pop(i)
# Verify placing this item won't reduce available locations, which would be a useless swap.
prev_state = swap_state.copy()
prev_loc_count = len(
multiworld.get_reachable_locations(prev_state))
swap_count += 1
swapped_items[placed_item.player, placed_item.name, unsafe] = swap_count
swap_state.collect(item_to_place, True)
new_loc_count = len(
multiworld.get_reachable_locations(swap_state))
reachable_items[placed_item.player].appendleft(
placed_item)
item_pool.append(placed_item)
if new_loc_count >= prev_loc_count:
# Add this item to the existing placement, and
# add the old item to the back of the queue
spot_to_fill = placements.pop(i)
# cleanup at the end to hopefully get better errors
cleanup_required = True
swap_count += 1
swapped_items[placed_item.player, placed_item.name, unsafe] = swap_count
reachable_items[placed_item.player].appendleft(
placed_item)
item_pool.append(placed_item)
# cleanup at the end to hopefully get better errors
cleanup_required = True
break
break
# Item can't be placed here, restore original item
location.item = placed_item
@@ -212,7 +249,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)
@@ -220,18 +257,31 @@ def fill_restrictive(multiworld: MultiWorld, base_state: CollectionState, locati
def remaining_fill(multiworld: MultiWorld,
locations: typing.List[Location],
itempool: typing.List[Item],
name: str = "Remaining") -> None:
name: str = "Remaining",
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))
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
@@ -252,7 +302,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)
@@ -284,13 +334,21 @@ def remaining_fill(multiworld: MultiWorld,
if unplaced_items and locations:
# There are leftover unplaceable items and locations that won't accept them
raise FillError(f"No more spots to place {len(unplaced_items)} items. Remaining locations are invalid.\n"
f"Unplaced items:\n"
f"{', '.join(str(item) for item in unplaced_items)}\n"
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)}")
if move_unplaceable_to_start_inventory:
last_batch = []
for item in unplaced_items:
logging.debug(f"Moved {item} to start_inventory to prevent fill failure.")
multiworld.push_precollected(item)
last_batch.append(multiworld.worlds[item.player].create_filler())
remaining_fill(multiworld, locations, unplaced_items, name + " Start Inventory Retry")
else:
raise FillError(f"No more spots to place {len(unplaced_items)} items. Remaining locations are invalid.\n"
f"Unplaced items:\n"
f"{', '.join(str(item) for item in unplaced_items)}\n"
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)}", multiworld=multiworld)
itempool.extend(unplaced_items)
@@ -304,19 +362,26 @@ def fast_fill(multiworld: MultiWorld,
return item_pool[placing:], fill_locations[placing:]
def accessibility_corrections(multiworld: MultiWorld, state: CollectionState, locations, pool=[]):
def accessibility_corrections(multiworld: MultiWorld,
state: CollectionState,
locations: list[Location],
pool: list[Item] | None = None) -> None:
if pool is None:
pool = []
maximum_exploration_state = sweep_from_pool(state, pool)
minimal_players = {player for player in multiworld.player_ids if multiworld.worlds[player].options.accessibility == "minimal"}
unreachable_locations = [location for location in multiworld.get_locations() if location.player in minimal_players and
minimal_players = {player for player in multiworld.player_ids if
multiworld.worlds[player].options.accessibility == "minimal"}
unreachable_locations = [location for location in multiworld.get_locations() if
location.player in minimal_players and
not location.can_reach(maximum_exploration_state)]
for location in unreachable_locations:
if (location.item is not None and location.item.advancement and location.address is not None and not
location.locked and location.item.player not in minimal_players):
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)
state.remove(location.item)
locations.append(location)
if pool and locations:
locations.sort(key=lambda loc: loc.progress_type != LocationProgressType.PRIORITY)
@@ -328,7 +393,7 @@ def inaccessible_location_rules(multiworld: MultiWorld, state: CollectionState,
unreachable_locations = [location for location in locations if not location.can_reach(maximum_exploration_state)]
if unreachable_locations:
def forbid_important_item_rule(item: Item):
return not ((item.classification & 0b0011) and multiworld.worlds[item.player].options.accessibility != 'minimal')
return not ((item.classification & 0b0011) and multiworld.worlds[item.player].options.accessibility != "minimal")
for location in unreachable_locations:
add_item_rule(location, forbid_important_item_rule)
@@ -349,7 +414,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:
@@ -420,7 +485,14 @@ def distribute_early_items(multiworld: MultiWorld,
return fill_locations, itempool
def distribute_items_restrictive(multiworld: MultiWorld) -> None:
def distribute_items_restrictive(multiworld: MultiWorld,
panic_method: typing.Literal["swap", "raise", "start_inventory"] = "swap") -> None:
assert all(item.location is None for item in multiworld.itempool), (
"At the start of distribute_items_restrictive, "
"there are items in the multiworld itempool that are already placed on locations:\n"
f"{[(item.location, item) for item in multiworld.itempool if item.location is not None]}"
)
fill_locations = sorted(multiworld.get_unfilled_locations())
multiworld.random.shuffle(fill_locations)
# get items to distribute
@@ -460,22 +532,85 @@ def distribute_items_restrictive(multiworld: MultiWorld) -> None:
nonlocal lock_later
lock_later.append(location)
single_player = multiworld.players == 1 and not multiworld.groups
if prioritylocations:
regular_progression = []
deprioritized_progression = []
for item in progitempool:
if item.deprioritized:
deprioritized_progression.append(item)
else:
regular_progression.append(item)
# "priority fill"
fill_restrictive(multiworld, multiworld.state, prioritylocations, progitempool,
single_player_placement=multiworld.players == 1, swap=False, on_place=mark_for_locking,
name="Priority")
# try without deprioritized items in the mix at all. This means they need to be collected into state first.
priority_fill_state = sweep_from_pool(multiworld.state, deprioritized_progression)
fill_restrictive(multiworld, priority_fill_state, prioritylocations, regular_progression,
single_player_placement=single_player, swap=False, on_place=mark_for_locking,
name="Priority", one_item_per_player=True, allow_partial=True)
if prioritylocations and regular_progression:
# retry with one_item_per_player off because some priority fills can fail to fill with that optimization
# deprioritized items are still not in the mix, so they need to be collected into state first.
# allow_partial should only be set if there is deprioritized progression to fall back on.
priority_retry_state = sweep_from_pool(multiworld.state, deprioritized_progression)
fill_restrictive(multiworld, priority_retry_state, prioritylocations, regular_progression,
single_player_placement=single_player, swap=False, on_place=mark_for_locking,
name="Priority Retry", one_item_per_player=False,
allow_partial=bool(deprioritized_progression))
if prioritylocations and deprioritized_progression:
# There are no more regular progression items that can be placed on any priority locations.
# We'd still prefer to place deprioritized progression items on priority locations over filler items.
# Since we're leaving out the remaining regular progression now, we need to collect it into state first.
priority_retry_2_state = sweep_from_pool(multiworld.state, regular_progression)
fill_restrictive(multiworld, priority_retry_2_state, prioritylocations, deprioritized_progression,
single_player_placement=single_player, swap=False, on_place=mark_for_locking,
name="Priority Retry 2", one_item_per_player=True, allow_partial=True)
if prioritylocations and deprioritized_progression:
# retry with deprioritized items AND without one_item_per_player optimisation
# Since we're leaving out the remaining regular progression now, we need to collect it into state first.
priority_retry_3_state = sweep_from_pool(multiworld.state, regular_progression)
fill_restrictive(multiworld, priority_retry_3_state, prioritylocations, deprioritized_progression,
single_player_placement=single_player, swap=False, on_place=mark_for_locking,
name="Priority Retry 3", one_item_per_player=False)
# restore original order of progitempool
progitempool[:] = [item for item in progitempool if not item.location]
accessibility_corrections(multiworld, multiworld.state, prioritylocations, progitempool)
defaultlocations = prioritylocations + defaultlocations
if progitempool:
# "advancement/progression fill"
fill_restrictive(multiworld, multiworld.state, defaultlocations, progitempool, single_player_placement=multiworld.players == 1,
name="Progression")
maximum_exploration_state = sweep_from_pool(multiworld.state)
if panic_method == "swap":
fill_restrictive(multiworld, maximum_exploration_state, defaultlocations, progitempool, swap=True,
name="Progression", single_player_placement=single_player)
elif panic_method == "raise":
fill_restrictive(multiworld, maximum_exploration_state, defaultlocations, progitempool, swap=False,
name="Progression", single_player_placement=single_player)
elif panic_method == "start_inventory":
fill_restrictive(multiworld, maximum_exploration_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.")
multiworld.push_precollected(item)
filleritempool.append(multiworld.worlds[item.player].create_filler())
logging.warning(f"{len(progitempool)} items moved to start inventory,"
f" due to failure in Progression fill step.")
progitempool[:] = []
else:
raise ValueError(f"Generator Panic Method {panic_method} not recognized.")
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)
@@ -486,16 +621,20 @@ def distribute_items_restrictive(multiworld: MultiWorld) -> None:
inaccessible_location_rules(multiworld, multiworld.state, defaultlocations)
remaining_fill(multiworld, excludedlocations, filleritempool, "Remaining Excluded")
remaining_fill(multiworld, excludedlocations, filleritempool, "Remaining Excluded",
move_unplaceable_to_start_inventory=panic_method=="start_inventory")
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
remaining_fill(multiworld, defaultlocations, restitempool)
remaining_fill(multiworld, defaultlocations, restitempool,
move_unplaceable_to_start_inventory=panic_method=="start_inventory")
unplaced = restitempool
unfilled = defaultlocations
@@ -509,6 +648,26 @@ def distribute_items_restrictive(multiworld: MultiWorld) -> None:
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
@@ -517,7 +676,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:
@@ -555,7 +714,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()
@@ -584,9 +743,9 @@ def balance_multiworld_progression(multiworld: MultiWorld) -> None:
if multiworld.worlds[player].options.progression_balancing > 0
}
if not balanceable_players:
logging.info('Skipping multiworld progression balancing.')
logging.info("Skipping multiworld progression balancing.")
else:
logging.info(f'Balancing multiworld progression for {len(balanceable_players)} Players.')
logging.info(f"Balancing multiworld progression for {len(balanceable_players)} Players.")
logging.debug(balanceable_players)
state: CollectionState = CollectionState(multiworld)
checked_locations: typing.Set[Location] = set()
@@ -612,7 +771,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:
@@ -685,7 +843,7 @@ def balance_multiworld_progression(multiworld: MultiWorld) -> None:
if player in threshold_percentages):
break
elif not balancing_sphere:
raise RuntimeError('Not all required items reachable. Something went terribly wrong here.')
raise RuntimeError("Not all required items reachable. Something went terribly wrong here.")
# Gather a set of locations which we can swap items into
unlocked_locations: typing.Dict[int, typing.Set[Location]] = collections.defaultdict(set)
for l in unchecked_locations:
@@ -701,12 +859,12 @@ def balance_multiworld_progression(multiworld: MultiWorld) -> None:
testing = items_to_test.pop()
reducing_state = state.copy()
for location in itertools.chain((
l for l in items_to_replace
if l.item.player == player
l for l in items_to_replace
if l.item.player == player
), 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):
@@ -775,52 +933,30 @@ def swap_location_item(location_1: Location, location_2: Location, check_locked:
location_2.item.location = location_2
def distribute_planned(multiworld: MultiWorld) -> None:
def warn(warning: str, force: typing.Union[bool, str]) -> None:
if force in [True, 'fail', 'failure', 'none', False, 'warn', 'warning']:
logging.warning(f'{warning}')
def parse_planned_blocks(multiworld: MultiWorld) -> dict[int, list[PlandoItemBlock]]:
def warn(warning: str, force: bool | str) -> None:
if isinstance(force, bool):
logging.warning(f"{warning}")
else:
logging.debug(f'{warning}')
logging.debug(f"{warning}")
def failed(warning: str, force: typing.Union[bool, str]) -> None:
if force in [True, 'fail', 'failure']:
def failed(warning: str, force: bool | str) -> None:
if force is True:
raise Exception(warning)
else:
warn(warning, force)
swept_state = multiworld.state.copy()
swept_state.sweep_for_events()
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)
for loc in multiworld.get_unfilled_locations():
if loc in reachable:
early_locations[loc.player].append(loc.name)
else: # not reachable with swept state
non_early_locations[loc.player].append(loc.name)
world_name_lookup = multiworld.world_name_lookup
block_value = typing.Union[typing.List[str], typing.Dict[str, typing.Any], str]
plando_blocks: typing.List[typing.Dict[str, typing.Any]] = []
player_ids = set(multiworld.player_ids)
plando_blocks: dict[int, list[PlandoItemBlock]] = dict()
player_ids: set[int] = set(multiworld.player_ids)
for player in player_ids:
for block in multiworld.plando_items[player]:
block['player'] = player
if 'force' not in block:
block['force'] = 'silent'
if 'from_pool' not in block:
block['from_pool'] = True
elif not isinstance(block['from_pool'], bool):
from_pool_type = type(block['from_pool'])
raise Exception(f'Plando "from_pool" has to be boolean, not {from_pool_type} for player {player}.')
if 'world' not in block:
target_world = False
else:
target_world = block['world']
plando_blocks[player] = []
for block in multiworld.worlds[player].options.plando_items:
new_block: PlandoItemBlock = PlandoItemBlock(player, block.from_pool, block.force)
target_world = block.world
if target_world is False or multiworld.players == 1: # target own world
worlds: typing.Set[int] = {player}
worlds: set[int] = {player}
elif target_world is True: # target any worlds besides own
worlds = set(multiworld.player_ids) - {player}
elif target_world is None: # target all worlds
@@ -829,156 +965,201 @@ def distribute_planned(multiworld: MultiWorld) -> None:
worlds = set()
for listed_world in target_world:
if listed_world not in world_name_lookup:
failed(f"Cannot place item to {target_world}'s world as that world does not exist.",
block['force'])
failed(f"Cannot place item to {listed_world}'s world as that world does not exist.",
block.force)
continue
worlds.add(world_name_lookup[listed_world])
elif type(target_world) == int: # target world by slot number
if target_world not in range(1, multiworld.players + 1):
failed(
f"Cannot place item in world {target_world} as it is not in range of (1, {multiworld.players})",
block['force'])
block.force)
continue
worlds = {target_world}
else: # target world by slot name
if target_world not in world_name_lookup:
failed(f"Cannot place item to {target_world}'s world as that world does not exist.",
block['force'])
block.force)
continue
worlds = {world_name_lookup[target_world]}
block['world'] = worlds
new_block.worlds = worlds
items: block_value = []
if "items" in block:
items = block["items"]
if 'count' not in block:
block['count'] = False
elif "item" in block:
items = block["item"]
if 'count' not in block:
block['count'] = 1
else:
failed("You must specify at least one item to place items with plando.", block['force'])
continue
items: list[str] | dict[str, typing.Any] = block.items
if isinstance(items, dict):
item_list: typing.List[str] = []
item_list: list[str] = []
for key, value in items.items():
if value is True:
value = multiworld.itempool.count(multiworld.worlds[player].create_item(key))
item_list += [key] * value
items = item_list
if isinstance(items, str):
items = [items]
block['items'] = items
new_block.items = items
locations: block_value = []
if 'location' in block:
locations = block['location'] # just allow 'location' to keep old yamls compatible
elif 'locations' in block:
locations = block['locations']
locations: list[str] = block.locations
if isinstance(locations, str):
locations = [locations]
if isinstance(locations, dict):
location_list = []
for key, value in locations.items():
location_list += [key] * value
locations = location_list
resolved_locations: list[Location] = []
for target_player in worlds:
locations_from_groups: list[str] = []
world_locations = multiworld.get_unfilled_locations(target_player)
for group in multiworld.worlds[target_player].location_name_groups:
if group in locations:
locations_from_groups.extend(multiworld.worlds[target_player].location_name_groups[group])
resolved_locations.extend(location for location in world_locations
if location.name in [*locations, *locations_from_groups])
new_block.locations = sorted(dict.fromkeys(locations))
new_block.resolved_locations = sorted(set(resolved_locations))
count = block.count
if not count:
count = (min(len(new_block.items), len(new_block.resolved_locations))
if new_block.resolved_locations else len(new_block.items))
if isinstance(count, int):
count = {"min": count, "max": count}
if "min" not in count:
count["min"] = 0
if "max" not in count:
count["max"] = (min(len(new_block.items), len(new_block.resolved_locations))
if new_block.resolved_locations else len(new_block.items))
new_block.count = count
plando_blocks[player].append(new_block)
return plando_blocks
def resolve_early_locations_for_planned(multiworld: MultiWorld):
def warn(warning: str, force: bool | str) -> None:
if isinstance(force, bool):
logging.warning(f"{warning}")
else:
logging.debug(f"{warning}")
def failed(warning: str, force: bool | str) -> None:
if force is True:
raise Exception(warning)
else:
warn(warning, force)
swept_state = multiworld.state.copy()
swept_state.sweep_for_advancements()
reachable = frozenset(multiworld.get_reachable_locations(swept_state))
early_locations: dict[int, list[Location]] = collections.defaultdict(list)
non_early_locations: dict[int, list[Location]] = collections.defaultdict(list)
for loc in multiworld.get_unfilled_locations():
if loc in reachable:
early_locations[loc.player].append(loc)
else: # not reachable with swept state
non_early_locations[loc.player].append(loc)
for player in multiworld.plando_item_blocks:
removed = []
for block in multiworld.plando_item_blocks[player]:
locations = block.locations
resolved_locations = block.resolved_locations
worlds = block.worlds
if "early_locations" in locations:
locations.remove("early_locations")
for target_player in worlds:
locations += early_locations[target_player]
resolved_locations += early_locations[target_player]
if "non_early_locations" in locations:
locations.remove("non_early_locations")
for target_player in worlds:
locations += non_early_locations[target_player]
resolved_locations += non_early_locations[target_player]
block['locations'] = list(dict.fromkeys(locations))
if block.count["max"] > len(block.items):
count = block.count["max"]
failed(f"Plando count {count} greater than items specified", block.force)
block.count["max"] = len(block.items)
if block.count["min"] > len(block.items):
block.count["min"] = len(block.items)
if block.count["max"] > len(block.resolved_locations) > 0:
count = block.count["max"]
failed(f"Plando count {count} greater than locations specified", block.force)
block.count["max"] = len(block.resolved_locations)
if block.count["min"] > len(block.resolved_locations):
block.count["min"] = len(block.resolved_locations)
block.count["target"] = multiworld.random.randint(block.count["min"],
block.count["max"])
if not block['count']:
block['count'] = (min(len(block['items']), len(block['locations'])) if
len(block['locations']) > 0 else len(block['items']))
if isinstance(block['count'], int):
block['count'] = {'min': block['count'], 'max': block['count']}
if 'min' not in block['count']:
block['count']['min'] = 0
if 'max' not in block['count']:
block['count']['max'] = (min(len(block['items']), len(block['locations'])) if
len(block['locations']) > 0 else len(block['items']))
if block['count']['max'] > len(block['items']):
count = block['count']
failed(f"Plando count {count} greater than items specified", block['force'])
block['count'] = len(block['items'])
if block['count']['max'] > len(block['locations']) > 0:
count = block['count']
failed(f"Plando count {count} greater than locations specified", block['force'])
block['count'] = len(block['locations'])
block['count']['target'] = multiworld.random.randint(block['count']['min'], block['count']['max'])
if not block.count["target"]:
removed.append(block)
if block['count']['target'] > 0:
plando_blocks.append(block)
for block in removed:
multiworld.plando_item_blocks[player].remove(block)
def distribute_planned_blocks(multiworld: MultiWorld, plando_blocks: list[PlandoItemBlock]):
def warn(warning: str, force: bool | str) -> None:
if isinstance(force, bool):
logging.warning(f"{warning}")
else:
logging.debug(f"{warning}")
def failed(warning: str, force: bool | str) -> None:
if force is True:
raise Exception(warning)
else:
warn(warning, force)
# shuffle, but then sort blocks by number of locations minus number of items,
# so less-flexible blocks get priority
multiworld.random.shuffle(plando_blocks)
plando_blocks.sort(key=lambda block: (len(block['locations']) - block['count']['target']
if len(block['locations']) > 0
else len(multiworld.get_unfilled_locations(player)) - block['count']['target']))
plando_blocks.sort(key=lambda block: (len(block.resolved_locations) - block.count["target"]
if len(block.resolved_locations) > 0
else len(multiworld.get_unfilled_locations(block.player)) -
block.count["target"]))
for placement in plando_blocks:
player = placement['player']
player = placement.player
try:
worlds = placement['world']
locations = placement['locations']
items = placement['items']
maxcount = placement['count']['target']
from_pool = placement['from_pool']
worlds = placement.worlds
locations = placement.resolved_locations
items = placement.items
maxcount = placement.count["target"]
from_pool = placement.from_pool
candidates = list(multiworld.get_unfilled_locations_for_players(locations, sorted(worlds)))
multiworld.random.shuffle(candidates)
multiworld.random.shuffle(items)
count = 0
err: typing.List[str] = []
successful_pairs: typing.List[typing.Tuple[Item, Location]] = []
for item_name in items:
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))
candidates.remove(location)
count = count + 1
break
else:
err.append(f"Can't place item at {location} due to fill condition not met.")
else:
err.append(f"{item_name} not allowed at {location}.")
else:
err.append(f"Cannot place {item_name} into already filled location {location}.")
item_candidates = []
if from_pool:
instances = [item for item in multiworld.itempool if item.player == player and item.name in items]
for item in multiworld.random.sample(items, maxcount):
candidate = next((i for i in instances if i.name == item), None)
if candidate is None:
warn(f"Could not remove {item} from pool for {multiworld.player_name[player]} as "
f"it's already missing from it", placement.force)
candidate = multiworld.worlds[player].create_item(item)
else:
err.append(f"Mismatch between {item_name} and {location}, only one is an event.")
if count == maxcount:
break
if count < placement['count']['min']:
m = placement['count']['min']
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:
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'])
multiworld.itempool.remove(candidate)
instances.remove(candidate)
item_candidates.append(candidate)
else:
item_candidates = [multiworld.worlds[player].create_item(item)
for item in multiworld.random.sample(items, maxcount)]
if any(item.code is None for item in item_candidates) \
and not all(item.code is None for item in item_candidates):
failed(f"Plando block for player {player} ({multiworld.player_name[player]}) contains both "
f"event items and non-event items. "
f"Event items: {[item for item in item_candidates if item.code is None]}, "
f"Non-event items: {[item for item in item_candidates if item.code is not None]}",
placement.force)
continue
else:
is_real = item_candidates[0].code is not None
candidates = [candidate for candidate in locations if candidate.item is None
and bool(candidate.address) == is_real]
multiworld.random.shuffle(candidates)
allstate = multiworld.get_all_state(False)
mincount = placement.count["min"]
allowed_margin = len(item_candidates) - mincount
fill_restrictive(multiworld, allstate, candidates, item_candidates, lock=True,
allow_partial=True, name="Plando Main Fill")
if len(item_candidates) > allowed_margin:
failed(f"Could not place {len(item_candidates)} "
f"of {mincount + allowed_margin} item(s) "
f"for {multiworld.player_name[player]}, "
f"remaining items: {item_candidates}",
placement.force)
if from_pool:
multiworld.itempool.extend([item for item in item_candidates if item.code is not None])
except Exception as e:
raise Exception(
f"Error running plando for player {player} ({multiworld.player_name[player]})") from e

View File

@@ -1,36 +1,32 @@
from __future__ import annotations
import argparse
import copy
import logging
import os
import random
import string
import sys
import urllib.parse
import urllib.request
from collections import Counter
from typing import Any, Dict, Tuple, Union
from itertools import chain
from typing import Any
import ModuleUpdate
ModuleUpdate.update()
import copy
import Utils
import Options
from BaseClasses import seeddigits, get_seed, PlandoOptions
from Main import main as ERmain
from settings import get_settings
from Utils import parse_yamls, version_tuple, __version__, tuplize_version
from worlds.alttp.EntranceRandomizer import parse_arguments
from worlds.alttp.Text import TextTable
from worlds.AutoWorld import AutoWorldRegister
from worlds.generic import PlandoConnection
from worlds import failed_world_loads
def mystery_argparse():
options = get_settings()
defaults = options.generator
def mystery_argparse(argv: list[str] | None = None) -> argparse.Namespace:
from settings import get_settings
settings = get_settings()
defaults = settings.generator
parser = argparse.ArgumentParser(description="CMD Generation Interface, defaults come from host.yaml.")
parser.add_argument('--weights_file_path', default=defaults.weights_file_path,
@@ -42,41 +38,56 @@ def mystery_argparse():
parser.add_argument('--seed', help='Define seed number to generate.', type=int)
parser.add_argument('--multi', default=defaults.players, type=lambda value: max(int(value), 1))
parser.add_argument('--spoiler', type=int, default=defaults.spoiler)
parser.add_argument('--outputpath', default=options.general_options.output_path,
parser.add_argument('--outputpath', default=settings.general_options.output_path,
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",
help="Skips generation assertion and output stages and skips multidata and spoiler output. "
"Intended for debugging and testing purposes.")
args = parser.parse_args()
parser.add_argument("--spoiler_only", action="store_true",
help="Skips generation assertion and multidata, outputting only a spoiler log. "
"Intended for debugging and testing purposes.")
args = parser.parse_args(argv)
if args.skip_output and args.spoiler_only:
parser.error("Cannot mix --skip_output and --spoiler_only")
elif args.spoiler == 0 and args.spoiler_only:
parser.error("Cannot use --spoiler_only when --spoiler=0. Use --skip_output or set --spoiler to a different value")
if not os.path.isabs(args.weights_file_path):
args.weights_file_path = os.path.join(args.player_files_path, args.weights_file_path)
if not os.path.isabs(args.meta_file_path):
args.meta_file_path = os.path.join(args.player_files_path, args.meta_file_path)
args.plando: PlandoOptions = PlandoOptions.from_option_string(args.plando)
return args, options
args.plando = PlandoOptions.from_option_string(args.plando)
return args
def get_seed_name(random_source) -> str:
return f"{random_source.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits)
def main(args=None, callback=ERmain):
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, options = mystery_argparse()
else:
options = get_settings()
args = mystery_argparse()
seed = get_seed(args.seed)
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)
@@ -84,7 +95,7 @@ def main(args=None, callback=ERmain):
logging.info("Race mode enabled. Using non-deterministic random source.")
random.seed() # reset to time-based random source
weights_cache: Dict[str, Tuple[Any, ...]] = {}
weights_cache: dict[str, tuple[Any, ...]] = {}
if args.weights_file_path and os.path.exists(args.weights_file_path):
try:
weights_cache[args.weights_file_path] = read_weights_yamls(args.weights_file_path)
@@ -107,17 +118,30 @@ def main(args=None, callback=ERmain):
raise Exception("Cannot mix --sameoptions with --meta")
else:
meta_weights = None
player_id = 1
player_files = {}
player_id: int = 1
player_files: dict[int, str] = {}
player_errors: list[str] = []
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
logging.exception(f"Exception reading weights in file {fname}")
player_errors.append(
f"{len(player_errors) + 1}. "
f"File {fname} is invalid. Please fix your yaml.\n{Utils.get_all_causes(e)}"
)
# sort dict for consistent results across platforms:
weights_cache = {key: value for key, value in sorted(weights_cache.items(), key=lambda k: k[0].casefold())}
@@ -132,6 +156,10 @@ def main(args=None, callback=ERmain):
args.multi = max(player_id - 1, args.multi)
if args.multi == 0:
if player_errors:
errors = "\n\n".join(player_errors)
raise ValueError(f"Encountered {len(player_errors)} error(s) in player files. "
f"See logs for full tracebacks.\n\n{errors}")
raise ValueError(
"No individual player files found and number of players is 0. "
"Provide individual player files or specify the number of players via host.yaml or --multi."
@@ -141,22 +169,19 @@ def main(args=None, callback=ERmain):
f"{seed_name} Seed {seed} with plando: {args.plando}")
if not weights_cache:
if player_errors:
errors = "\n\n".join(player_errors)
raise ValueError(f"Encountered {len(player_errors)} error(s) in player files. "
f"See logs for full tracebacks.\n\n{errors}")
raise Exception(f"No weights found. "
f"Provide a general weights file ({args.weights_file_path}) or individual player files. "
f"A mix is also permitted.")
erargs = parse_arguments(['--multi', str(args.multi)])
erargs.seed = seed
erargs.plando_options = args.plando
erargs.spoiler = args.spoiler
erargs.race = args.race
erargs.outputname = seed_name
erargs.outputpath = args.outputpath
erargs.skip_prog_balancing = args.skip_prog_balancing
erargs.skip_output = args.skip_output
settings_cache: Dict[str, Tuple[argparse.Namespace, ...]] = \
{fname: (tuple(roll_settings(yaml, args.plando) for yaml in yamls) if args.sameoptions else None)
for fname, yamls in weights_cache.items()}
from worlds.AutoWorld import AutoWorldRegister
args.outputname = seed_name
args.sprite = dict.fromkeys(range(1, args.multi+1), None)
args.sprite_pool = dict.fromkeys(range(1, args.multi+1), None)
args.name = {}
if meta_weights:
for category_name, category_dict in meta_weights.items():
@@ -172,73 +197,98 @@ def main(args=None, callback=ERmain):
yaml[category][key] = option
elif category_name not in yaml:
logging.warning(f"Meta: Category {category_name} is not present in {path}.")
elif key == "triggers":
if "triggers" not in yaml[category_name]:
yaml[category_name][key] = []
for trigger in option:
yaml[category_name][key].append(trigger)
else:
yaml[category_name][key] = option
player_path_cache = {}
settings_cache: dict[str, tuple[argparse.Namespace, ...] | None] = {fname: None for fname in weights_cache}
if args.sameoptions:
for fname, yamls in weights_cache.items():
try:
settings_cache[fname] = tuple(roll_settings(yaml, args.plando) for yaml in yamls)
except Exception as e:
logging.exception(f"Exception reading settings in file {fname}")
player_errors.append(
f"{len(player_errors) + 1}. "
f"File {fname} is invalid. Please fix your yaml.\n{Utils.get_all_causes(e)}"
)
# Exit early here to avoid throwing the same errors again later
if player_errors:
errors = "\n\n".join(player_errors)
raise ValueError(f"Encountered {len(player_errors)} error(s) in player files. "
f"See logs for full tracebacks.\n\n{errors}")
player_path_cache: dict[int, str] = {}
for player in range(1, args.multi + 1):
player_path_cache[player] = player_files.get(player, args.weights_file_path)
name_counter = Counter()
erargs.player_options = {}
name_counter: Counter[str] = Counter()
args.player_options = {}
player = 1
while player <= args.multi:
path = player_path_cache[player]
if path:
if not path:
player_errors.append(f'No weights specified for player {player}')
player += 1
continue
for doc_index, yaml in enumerate(weights_cache[path]):
name = yaml.get("name")
try:
settings: Tuple[argparse.Namespace, ...] = settings_cache[path] if settings_cache[path] else \
tuple(roll_settings(yaml, args.plando) for yaml in weights_cache[path])
for settingsObject in settings:
for k, v in vars(settingsObject).items():
if v is not None:
try:
getattr(erargs, k)[player] = v
except AttributeError:
setattr(erargs, k, {player: v})
except Exception as e:
raise Exception(f"Error setting {k} to {v} for player {player}") from e
# Use the cached settings object if it exists, otherwise roll settings within the try-catch
# Invariant: settings_cache[path] and weights_cache[path] have the same length
cached = settings_cache[path]
settings_object: argparse.Namespace = (cached[doc_index] if cached else roll_settings(yaml, args.plando))
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
erargs.name[player] = os.path.splitext(os.path.split(path)[-1])[0]
erargs.name[player] = handle_name(erargs.name[player], player, name_counter)
for k, v in vars(settings_object).items():
if v is not None:
try:
getattr(args, k)[player] = v
except AttributeError:
setattr(args, k, {player: v})
except Exception as e:
raise Exception(f"Error setting {k} to {v} for player {player}") from e
player += 1
except Exception as e:
raise ValueError(f"File {path} is invalid. Please fix your yaml.") from e
else:
raise RuntimeError(f'No weights specified for player {player}')
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}
# name was not specified
if player not in args.name:
if path == args.weights_file_path:
# weights file, so we need to make the name unique
args.name[player] = f"Player{player}"
else:
logging.debug(f"No player settings defined for option '{option}'")
# use the filename
args.name[player] = os.path.splitext(os.path.split(path)[-1])[0]
args.name[player] = handle_name(args.name[player], player, name_counter)
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)
except Exception as e:
logging.exception(f"Exception reading settings in file {path} document #{doc_index + 1} "
f"(name: {args.name.get(player, name)})")
player_errors.append(
f"{len(player_errors) + 1}. "
f"File {path} document #{doc_index + 1} (name: {args.name.get(player, name)}) is invalid. "
f"Please fix your yaml.\n{Utils.get_all_causes(e)}")
return callback(erargs, seed)
# increment for each yaml document in the file
player += 1
if len(set(name.lower() for name in args.name.values())) != len(args.name):
player_errors.append(
f"{len(player_errors) + 1}. "
f"Names have to be unique. Names: {Counter(name.lower() for name in args.name.values())}"
)
if player_errors:
errors = "\n\n".join(player_errors)
raise ValueError(f"Encountered {len(player_errors)} error(s) in player files. "
f"See logs for full tracebacks.\n\n{errors}")
return args, seed
def read_weights_yamls(path) -> Tuple[Any, ...]:
def read_weights_yamls(path) -> tuple[Any, ...]:
try:
if urllib.parse.urlparse(path).scheme in ('https', 'file'):
yaml = str(urllib.request.urlopen(path).read(), "utf-8-sig")
@@ -248,7 +298,20 @@ def read_weights_yamls(path) -> Tuple[Any, ...]:
except Exception as e:
raise Exception(f"Failed to read weights ({path})") from e
return tuple(parse_yamls(yaml))
from yaml.error import MarkedYAMLError
try:
return tuple(parse_yamls(yaml))
except MarkedYAMLError as ex:
if ex.problem_mark:
lines = yaml.splitlines()
if ex.context_mark:
relevant_lines = "\n".join(lines[ex.context_mark.line:ex.problem_mark.line+1])
else:
relevant_lines = lines[ex.problem_mark.line]
error_line = " " * ex.problem_mark.column + "^"
raise Exception(f"{ex.context} {ex.problem} on line {ex.problem_mark.line}:"
f"\n{relevant_lines}\n{error_line}")
raise ex
def interpret_on_off(value) -> bool:
@@ -288,51 +351,76 @@ def get_choice(option, root, value=None) -> Any:
raise RuntimeError(f"All options specified in \"{option}\" are weighted as zero.")
class SafeDict(dict):
def __missing__(self, key):
return '{' + key + '}'
class SafeFormatter(string.Formatter):
def get_value(self, key, args, kwargs):
if isinstance(key, int):
if key < len(args):
return args[key]
else:
return "{" + str(key) + "}"
else:
return kwargs.get(key, "{" + key + "}")
def handle_name(name: str, player: int, name_counter: Counter):
def handle_name(name: str, player: int, name_counter: Counter[str]):
name_counter[name.lower()] += 1
number = name_counter[name.lower()]
new_name = "%".join([x.replace("%number%", "{number}").replace("%player%", "{player}") for x in name.split("%%")])
new_name = string.Formatter().vformat(new_name, (), SafeDict(number=number,
NUMBER=(number if number > 1 else ''),
player=player,
PLAYER=(player if player > 1 else '')))
new_name = SafeFormatter().vformat(new_name, (), {"number": number,
"NUMBER": (number if number > 1 else ''),
"player": player,
"PLAYER": (player if player > 1 else '')})
# Run .strip twice for edge case where after the initial .slice new_name has a leading whitespace.
# Could cause issues for some clients that cannot handle the additional whitespace.
new_name = new_name.strip()[:16].strip()
if new_name == "Archipelago":
raise Exception(f"You cannot name yourself \"{new_name}\"")
return new_name
def roll_percentage(percentage: Union[int, float]) -> bool:
"""Roll a percentage chance.
percentage is expected to be in range [0, 100]"""
return random.random() < (float(percentage) / 100)
def update_weights(weights: dict, new_weights: dict, update_type: str, name: str) -> dict:
logging.debug(f'Applying {new_weights}')
cleaned_weights = {}
for option in new_weights:
option_name = option.lstrip("+")
option_name = option.lstrip("+-")
if option.startswith("+") and option_name in weights:
cleaned_value = weights[option_name]
new_value = new_weights[option]
if isinstance(new_value, (set, dict)):
if isinstance(new_value, set):
cleaned_value.update(new_value)
elif isinstance(new_value, list):
cleaned_value.extend(new_value)
elif isinstance(new_value, dict):
counter_value = Counter(cleaned_value)
counter_value.update(new_value)
cleaned_value = dict(counter_value)
else:
raise Exception(f"Cannot apply merge to non-dict, set, or list type {option_name},"
f" received {type(new_value).__name__}.")
cleaned_weights[option_name] = cleaned_value
elif option.startswith("-") and option_name in weights:
cleaned_value = weights[option_name]
new_value = new_weights[option]
if isinstance(new_value, set):
cleaned_value.difference_update(new_value)
elif isinstance(new_value, list):
for element in new_value:
cleaned_value.remove(element)
elif isinstance(new_value, dict):
counter_value = Counter(cleaned_value)
counter_value.subtract(new_value)
cleaned_value = dict(counter_value)
else:
raise Exception(f"Cannot apply remove to non-dict, set, or list type {option_name},"
f" received {type(new_value).__name__}.")
cleaned_weights[option_name] = cleaned_value
else:
cleaned_weights[option_name] = new_weights[option]
# Options starting with + and - may modify values in-place, and new_weights may be shared by multiple slots
# using the same .yaml, so ensure that the new value is a copy.
cleaned_value = copy.deepcopy(new_weights[option])
cleaned_weights[option_name] = cleaned_value
new_options = set(cleaned_weights) - set(weights)
weights.update(cleaned_weights)
if new_options:
@@ -343,7 +431,9 @@ def update_weights(weights: dict, new_weights: dict, update_type: str, name: str
return weights
def roll_meta_option(option_key, game: str, category_dict: Dict) -> Any:
def roll_meta_option(option_key, game: str, category_dict: dict) -> Any:
from worlds import AutoWorldRegister
if not game:
return get_choice(option_key, category_dict)
if game in AutoWorldRegister.world_types:
@@ -353,6 +443,8 @@ def roll_meta_option(option_key, game: str, category_dict: Dict) -> Any:
if options[option_key].supports_weighting:
return get_choice(option_key, category_dict)
return category_dict[option_key]
if option_key == "triggers":
return category_dict[option_key]
raise Options.OptionError(f"Error generating meta option {option_key} for {game}.")
@@ -362,7 +454,7 @@ def roll_linked_options(weights: dict) -> dict:
if "name" not in option_set:
raise ValueError("One of your linked options does not have a name.")
try:
if roll_percentage(option_set["percentage"]):
if Options.roll_percentage(option_set["percentage"]):
logging.debug(f"Linked option {option_set['name']} triggered.")
new_options = option_set["options"]
for category_name, category_options in new_options.items():
@@ -395,7 +487,7 @@ def roll_triggers(weights: dict, triggers: list, valid_keys: set) -> dict:
trigger_result = get_choice("option_result", option_set)
result = get_choice(key, currently_targeted_weights)
currently_targeted_weights[key] = result
if result == trigger_result and roll_percentage(get_choice("percentage", option_set, 100)):
if result == trigger_result and Options.roll_percentage(get_choice("percentage", option_set, 100)):
for category_name, category_options in option_set["options"].items():
currently_targeted_weights = weights
if category_name:
@@ -408,30 +500,40 @@ def roll_triggers(weights: dict, triggers: list, valid_keys: set) -> dict:
return weights
def handle_option(ret: argparse.Namespace, game_weights: dict, option_key: str, option: type(Options.Option), plando_options: PlandoOptions):
def handle_option(ret: argparse.Namespace, game_weights: dict, option_key: str, option: type[Options.Option], plando_options: PlandoOptions):
try:
if option_key in game_weights:
if not option.supports_weighting:
player_option = option.from_any(game_weights[option_key])
else:
player_option = option.from_any(get_choice(option_key, game_weights))
del game_weights[option_key]
else:
player_option = option.from_any(option.default) # call the from_any here to support default "random"
setattr(ret, option_key, player_option)
except Exception as e:
raise Options.OptionError(f"Error generating option {option_key} in {ret.game}") from e
else:
from worlds import AutoWorldRegister
player_option.verify(AutoWorldRegister.world_types[ret.game], ret.name, plando_options)
def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.bosses):
"""
Roll options from specified weights, usually originating from a .yaml options file.
Important note:
The same weights dict is shared between all slots using the same yaml (e.g. generic weights file for filler slots).
This means it should never be modified without making a deepcopy first.
"""
from worlds import AutoWorldRegister
if "linked_options" in weights:
weights = roll_linked_options(weights)
valid_trigger_names = set()
valid_keys = {"triggers"}
if "triggers" in weights:
weights = roll_triggers(weights, weights["triggers"], valid_trigger_names)
weights = roll_triggers(weights, weights["triggers"], valid_keys)
requirements = weights.get("requires", {})
if requirements:
@@ -444,14 +546,34 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b
if required_plando_options:
raise Exception(f"Settings reports required plando module {str(required_plando_options)}, "
f"which is not enabled.")
games = requirements.get("game", {})
for game, version in games.items():
if game not in AutoWorldRegister.world_types:
continue
if not version:
raise Exception(f"Invalid version for game {game}: {version}.")
if isinstance(version, str):
version = {"min": version}
if "min" in version and tuplize_version(version["min"]) > AutoWorldRegister.world_types[game].world_version:
raise Exception(f"Settings reports required version of world \"{game}\" is at least {version['min']}, "
f"however world is of version "
f"{AutoWorldRegister.world_types[game].world_version.as_simple_string()}.")
if "max" in version and tuplize_version(version["max"]) < AutoWorldRegister.world_types[game].world_version:
raise Exception(f"Settings reports required version of world \"{game}\" is no later than {version['max']}, "
f"however world is of version "
f"{AutoWorldRegister.world_types[game].world_version.as_simple_string()}.")
ret = argparse.Namespace()
for option_key in Options.PerGameCommonOptions.type_hints:
if option_key in weights and option_key not in Options.CommonOptions.type_hints:
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]
if picks[0] in failed_world_loads:
raise Exception(f"No functional world found to handle game {ret.game}. "
@@ -466,12 +588,14 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b
world_type = AutoWorldRegister.world_types[ret.game]
game_weights = weights[ret.game]
if any(weight.startswith("+") for weight in game_weights) or \
any(weight.startswith("+") for weight in weights):
raise Exception(f"Merge tag cannot be used outside of trigger contexts.")
for weight in chain(game_weights, weights):
if weight.startswith("+"):
raise Exception(f"Merge tag cannot be used outside of trigger contexts. Found {weight}")
if weight.startswith("-"):
raise Exception(f"Remove tag cannot be used outside of trigger contexts. Found {weight}")
if "triggers" in game_weights:
weights = roll_triggers(weights, game_weights["triggers"], valid_trigger_names)
weights = roll_triggers(weights, game_weights["triggers"], valid_keys)
game_weights = weights[ret.game]
ret.name = get_choice('name', weights)
@@ -480,42 +604,24 @@ 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)
for option_key in game_weights:
if option_key in {"triggers", *valid_trigger_names}:
continue
logging.warning(f"{option_key} is not a valid option name for {ret.game} and is not present in triggers.")
if PlandoOptions.items in plando_options:
ret.plando_items = game_weights.get("plando_items", [])
valid_keys.add(option_key)
if ret.game == "A Link to the Past":
roll_alttp_settings(ret, game_weights, plando_options)
if PlandoOptions.connections in plando_options:
ret.plando_connections = []
options = game_weights.get("plando_connections", [])
for placement in options:
if roll_percentage(get_choice("percentage", placement, 100)):
ret.plando_connections.append(PlandoConnection(
get_choice("entrance", placement),
get_choice("exit", placement),
get_choice("direction", placement, "both")
))
# 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
def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
ret.plando_texts = {}
if PlandoOptions.texts in plando_options:
tt = TextTable()
tt.removeUnwantedText()
options = weights.get("plando_texts", [])
for placement in options:
if roll_percentage(get_choice_legacy("percentage", placement, 100)):
at = str(get_choice_legacy("at", placement))
if at not in tt:
raise Exception(f"No text target \"{at}\" found.")
ret.plando_texts[at] = str(get_choice_legacy("text", placement))
def roll_alttp_settings(ret: argparse.Namespace, weights):
ret.sprite_pool = weights.get('sprite_pool', [])
ret.sprite = get_choice_legacy('sprite', weights, "Link")
if 'random_sprite_on_event' in weights:
@@ -543,7 +649,9 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
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

View File

@@ -1,8 +0,0 @@
import ModuleUpdate
import Utils
from worlds.kh2.Client import launch
ModuleUpdate.update()
if __name__ == '__main__':
Utils.init_logging("KH2Client", exception_logger="Client")
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

@@ -1,51 +1,62 @@
"""
Archipelago launcher for bundled app.
Archipelago Launcher
* if run with APBP as argument, launch corresponding client.
* if run with executable as argument, run it passing argv[2:] as arguments
* if run without arguments, open launcher GUI
* If run with a patch file as argument, launch corresponding client with the patch file as an argument.
* If run with component name as argument, run it passing argv[2:] as arguments.
* If run without arguments or unknown arguments, open launcher GUI.
Scroll down to components= to add components to the launcher as well as setup.py
Additional components can be added to worlds.LauncherComponents.components.
"""
import argparse
import itertools
import logging
import multiprocessing
import os
import shlex
import subprocess
import sys
import urllib.parse
import webbrowser
from collections.abc import Callable, Sequence
from os.path import isfile
from shutil import which
from typing import Sequence, Union, Optional
import Utils
import settings
from worlds.LauncherComponents import Component, components, Type, SuffixIdentifier, icon_paths
from typing import Any
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)
if __name__ == "__main__":
init_logging('Launcher')
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 \
which('xdg-open') or which('gnome-open') or which('kde-open')
subprocess.Popen([exe, file])
elif is_macos:
exe = which("open")
subprocess.Popen([exe, file])
else:
webbrowser.open(file)
return
env = os.environ
if "LD_LIBRARY_PATH" in env:
env = env.copy()
del env["LD_LIBRARY_PATH"] # exe is a system binary, so reset LD_LIBRARY_PATH
subprocess.Popen([exe, file], env=env)
def open_patch():
suffixes = []
@@ -68,12 +79,17 @@ def open_patch():
launch([*exe, file], component.cli)
def generate_yamls():
def generate_yamls(*args):
from Options import generate_yaml_templates
parser = argparse.ArgumentParser(description="Generate Template Options", usage="[-h] [--skip_open_folder]")
parser.add_argument("--skip_open_folder", action="store_true")
args = parser.parse_args(args)
target = Utils.user_path("Players", "Templates")
generate_yaml_templates(target, False)
open_folder(target)
if not args.skip_open_folder:
open_folder(target)
def browse_files():
@@ -83,12 +99,20 @@ def browse_files():
def open_folder(folder_path):
if is_linux:
exe = which('xdg-open') or which('gnome-open') or which('kde-open')
subprocess.Popen([exe, folder_path])
elif is_macos:
exe = which("open")
subprocess.Popen([exe, folder_path])
else:
webbrowser.open(folder_path)
return
if exe:
env = os.environ
if "LD_LIBRARY_PATH" in env:
env = env.copy()
del env["LD_LIBRARY_PATH"] # exe is a system binary, so reset LD_LIBRARY_PATH
subprocess.Popen([exe, folder_path], env=env)
else:
logging.warning(f"No file browser available to open {folder_path}")
def update_settings():
@@ -98,16 +122,51 @@ def update_settings():
components.extend([
# Functions
Component("Open host.yaml", func=open_host_yaml),
Component("Open Patch", func=open_patch),
Component("Generate Template Options", func=generate_yamls),
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),
Component("Open host.yaml", func=open_host_yaml,
description="Open the host.yaml file to change settings for generation, games, and more."),
Component("Open Patch", func=open_patch,
description="Open a patch file, downloaded from the room page or provided by the host."),
Component("Generate Template Options", func=generate_yamls,
description="Generate template YAMLs for currently installed games."),
Component("Archipelago Website", func=lambda: webbrowser.open("https://archipelago.gg/"),
description="Open archipelago.gg in your browser."),
Component("Discord Server", icon="discord", func=lambda: webbrowser.open("https://discord.gg/8Z65BR2"),
description="Join the Discord server to play public multiworlds, report issues, or just chat!"),
Component("Unrated/18+ Discord Server", icon="discord",
func=lambda: webbrowser.open("https://discord.gg/fqvNCCRsu4"),
description="Find unrated and 18+ games in the After Dark Discord server."),
Component("Browse Files", func=browse_files,
description="Open the Archipelago installation folder in your file browser."),
])
def identify(path: Union[None, str]):
def handle_uri(path: str) -> tuple[list[Component], Component]:
url = urllib.parse.urlparse(path)
queries = urllib.parse.parse_qs(url.query)
client_components = []
text_client_component = None
game = queries["game"][0]
for component in components:
if component.supports_uri and component.game_name == game:
client_components.append(component)
elif component.display_name == "Text Client":
text_client_component = component
return client_components, text_client_component
def build_uri_popup(component_list: list[Component], launch_args: tuple[str, ...]) -> None:
from kvui import ButtonsPrompt
component_options = {
component.display_name: component for component in component_list
}
popup = ButtonsPrompt("Connect to Multiworld",
"Select client to open and connect with.",
lambda component_name: run_component(component_options[component_name], *launch_args),
*component_options.keys())
popup.open()
def identify(path: None | str) -> tuple[None | str, None | Component]:
if path is None:
return None, None
for component in components:
@@ -118,7 +177,7 @@ def identify(path: Union[None, str]):
return None, None
def get_exe(component: Union[str, Component]) -> Optional[Sequence[str]]:
def get_exe(component: str | Component) -> Sequence[str] | None:
if isinstance(component, str):
name = component
component = None
@@ -146,7 +205,8 @@ def get_exe(component: Union[str, Component]) -> Optional[Sequence[str]]:
def launch(exe, in_terminal=False):
if in_terminal:
if is_windows:
subprocess.Popen(['start', *exe], shell=True)
# intentionally using a window title with a space so it gets quoted and treated as a title
subprocess.Popen(["start", "Running Archipelago", *exe], shell=True)
return
elif is_linux:
terminal = which('x-terminal-emulator') or which('gnome-terminal') or which('xterm')
@@ -160,139 +220,301 @@ def launch(exe, in_terminal=False):
subprocess.Popen(exe)
def run_gui():
from kvui import App, ContainerLayout, GridLayout, Button, Label, ScrollBox, Widget
from kivy.uix.image import AsyncImage
from kivy.uix.relativelayout import RelativeLayout
def create_shortcut(button: Any, component: Component) -> None:
from pyshortcuts import make_shortcut
env = os.environ
if "APPIMAGE" in env:
script = env["ARGV0"]
wkdir = None # defaults to ~ on Linux
else:
script = sys.argv[0]
wkdir = Utils.local_path()
class Launcher(App):
script = f"{script} \"{component.display_name}\""
make_shortcut(script, name=f"Archipelago {component.display_name}", icon=local_path("data", "icon.ico"),
startmenu=False, terminal=False, working_dir=wkdir, noexe=Utils.is_frozen())
button.menu.dismiss()
refresh_components: Callable[[], None] | None = None
def run_gui(launch_components: list[Component], args: Any) -> None:
from kvui import (ThemedApp, MDFloatLayout, MDGridLayout, ScrollBox)
from kivy.properties import ObjectProperty
from kivy.core.window import Window
from kivy.metrics import dp
from kivymd.uix.button import MDIconButton, MDButton
from kivymd.uix.card import MDCard
from kivymd.uix.menu import MDDropdownMenu
from kivymd.uix.snackbar import MDSnackbar, MDSnackbarText
from kivymd.uix.textfield import MDTextField
from kivy.lang.builder import Builder
class LauncherCard(MDCard):
component: Component | None
image: str
context_button: MDIconButton = ObjectProperty(None)
def __init__(self, *args, component: Component | None = None, image_path: str = "", **kwargs):
self.component = component
self.image = image_path
super().__init__(args, kwargs)
class Launcher(ThemedApp):
base_title: str = "Archipelago Launcher"
container: ContainerLayout
grid: GridLayout
top_screen: MDFloatLayout = ObjectProperty(None)
navigation: MDGridLayout = ObjectProperty(None)
grid: MDGridLayout = ObjectProperty(None)
button_layout: ScrollBox = ObjectProperty(None)
search_box: MDTextField = ObjectProperty(None)
cards: list[LauncherCard]
current_filter: Sequence[str | Type] | None
_tools = {c.display_name: c for c in components if c.type == Type.TOOL}
_clients = {c.display_name: c for c in components if c.type == Type.CLIENT}
_adjusters = {c.display_name: c for c in components if c.type == Type.ADJUSTER}
_miscs = {c.display_name: c for c in components if c.type == Type.MISC}
def __init__(self, ctx=None):
self.title = self.base_title
def __init__(self, ctx=None, components=None, args=None):
self.title = self.base_title + " " + Utils.__version__
self.ctx = ctx
self.icon = r"data/icon.png"
self.favorites = []
self.launch_components = components
self.launch_args = args
self.cards = []
self.current_filter = (Type.CLIENT, Type.TOOL, Type.ADJUSTER, Type.MISC)
persistent = Utils.persistent_load()
if "launcher" in persistent:
if "favorites" in persistent["launcher"]:
self.favorites.extend(persistent["launcher"]["favorites"])
if "filter" in persistent["launcher"]:
if persistent["launcher"]["filter"]:
filters = []
for filter in persistent["launcher"]["filter"].split(", "):
if filter == "favorites":
filters.append(filter)
else:
filters.append(Type[filter])
self.current_filter = filters
super().__init__()
def set_favorite(self, caller):
if caller.component.display_name in self.favorites:
self.favorites.remove(caller.component.display_name)
caller.icon = "star-outline"
else:
self.favorites.append(caller.component.display_name)
caller.icon = "star"
def build_card(self, component: Component) -> LauncherCard:
"""
Builds a card widget for a given component.
:param component: The component associated with the button.
:return: The created Card Widget.
"""
button_card = LauncherCard(component=component,
image_path=icon_paths[component.icon])
def open_menu(caller):
caller.menu.open()
menu_items = [
{
"text": "Add shortcut on desktop",
"leading_icon": "laptop",
"on_release": lambda: create_shortcut(button_card.context_button, component)
}
]
button_card.context_button.menu = MDDropdownMenu(caller=button_card.context_button, items=menu_items)
button_card.context_button.bind(on_release=open_menu)
return button_card
def _refresh_components(self, type_filter: Sequence[str | Type] | None = None) -> None:
if not type_filter:
type_filter = [Type.CLIENT, Type.ADJUSTER, Type.TOOL, Type.MISC]
favorites = "favorites" in type_filter
# clear before repopulating
assert self.button_layout, "must call `build` first"
tool_children = reversed(self.button_layout.layout.children)
for child in tool_children:
self.button_layout.layout.remove_widget(child)
cards = [card for card in self.cards if card.component.type in type_filter
or favorites and card.component.display_name in self.favorites]
self.current_filter = type_filter
for card in cards:
self.button_layout.layout.add_widget(card)
top = self.button_layout.children[0].y + self.button_layout.children[0].height \
- self.button_layout.height
scroll_percent = self.button_layout.convert_distance_to_scroll(0, top)
self.button_layout.scroll_y = max(0, min(1, scroll_percent[1]))
def filter_clients_by_type(self, caller: MDButton):
self._refresh_components(caller.type)
self.search_box.text = ""
def filter_clients_by_name(self, caller: MDTextField, name: str) -> None:
if len(name) == 0:
self._refresh_components(self.current_filter)
return
sub_matches = [
card for card in self.cards
if name.lower() in card.component.display_name.lower() and card.component.type != Type.HIDDEN
]
self.button_layout.layout.clear_widgets()
for card in sub_matches:
self.button_layout.layout.add_widget(card)
def build(self):
self.container = ContainerLayout()
self.grid = GridLayout(cols=2)
self.container.add_widget(self.grid)
self.grid.add_widget(Label(text="General", size_hint_y=None, height=40))
self.grid.add_widget(Label(text="Clients", size_hint_y=None, height=40))
tool_layout = ScrollBox()
tool_layout.layout.orientation = "vertical"
self.grid.add_widget(tool_layout)
client_layout = ScrollBox()
client_layout.layout.orientation = "vertical"
self.grid.add_widget(client_layout)
self.top_screen = Builder.load_file(Utils.local_path("data/launcher.kv"))
self.grid = self.top_screen.ids.grid
self.navigation = self.top_screen.ids.navigation
self.button_layout = self.top_screen.ids.button_layout
self.search_box = self.top_screen.ids.search_box
self.set_colors()
self.top_screen.md_bg_color = self.theme_cls.backgroundColor
def build_button(component: Component) -> Widget:
"""
Builds a button widget for a given component.
global refresh_components
refresh_components = self._refresh_components
Args:
component (Component): The component associated with the button.
Window.bind(on_drop_file=self._on_drop_file)
Window.bind(on_keyboard=self._on_keyboard)
Returns:
None. The button is added to the parent grid layout.
for component in components:
self.cards.append(self.build_card(component))
"""
button = Button(text=component.display_name, size_hint_y=None, height=40)
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))
box_layout = RelativeLayout(size_hint_y=None, height=40)
box_layout.add_widget(button)
box_layout.add_widget(image)
return box_layout
return button
self._refresh_components(self.current_filter)
for (tool, client) in itertools.zip_longest(itertools.chain(
self._tools.items(), self._miscs.items(), self._adjusters.items()), self._clients.items()):
# column 1
if tool:
tool_layout.layout.add_widget(build_button(tool[1]))
# column 2
if client:
client_layout.layout.add_widget(build_button(client[1]))
# Uncomment to re-enable the Kivy console/live editor
# Ctrl-E to enable it, make sure numlock/capslock is disabled
# from kivy.modules.console import create_console
# create_console(Window, self.top_screen)
return self.container
return self.top_screen
def on_start(self):
if self.launch_components:
build_uri_popup(self.launch_components, self.launch_args)
self.launch_components = None
self.launch_args = None
@staticmethod
def component_action(button):
MDSnackbar(MDSnackbarText(text="Opening in a new window..."), y=dp(24), pos_hint={"center_x": 0.5},
size_hint_x=0.5).open()
if button.component.func:
button.component.func()
else:
launch(get_exe(button.component), button.component.cli)
def _on_drop_file(self, window: Window, filename: bytes, x: int, y: int) -> None:
""" When a patch file is dropped into the window, run the associated component. """
file, component = identify(filename.decode())
if file and component:
run_component(component, file)
else:
logging.warning(f"unable to identify component for {filename}")
def _on_keyboard(self, window: Window, key: int, scancode: int, codepoint: str, modifier: list[str]):
# Activate search as soon as we start typing, no matter if we are focused on the search box or not.
# Focus first, then capture the first character we type, otherwise it gets swallowed and lost.
# Limit text input to ASCII non-control characters (space bar to tilde).
if not self.search_box.focus:
self.search_box.focus = True
if key in range(32, 126):
self.search_box.text += codepoint
def _stop(self, *largs):
# ran into what appears to be https://groups.google.com/g/kivy-users/c/saWDLoYCSZ4 with PyCharm.
# Closing the window explicitly cleans it up.
self.root_window.close()
super()._stop(*largs)
Launcher().run()
def on_stop(self):
Utils.persistent_store("launcher", "favorites", self.favorites)
Utils.persistent_store("launcher", "filter", ", ".join(filter.name if isinstance(filter, Type) else filter
for filter in self.current_filter))
super().on_stop()
Launcher(components=launch_components, args=args).run()
# avoiding Launcher reference leak
# and don't try to do something with widgets after window closed
global refresh_components
refresh_components = None
def run_component(component: Component, *args):
if component.func:
component.func(*args)
if refresh_components:
refresh_components()
elif component.script_name:
subprocess.run([*get_exe(component.script_name), *args])
else:
logging.warning(f"Component {component} does not appear to be executable.")
def main(args: Optional[Union[argparse.Namespace, dict]] = None):
def main(args: argparse.Namespace | dict | None = None):
if isinstance(args, argparse.Namespace):
args = {k: v for k, v in args._get_kwargs()}
elif not args:
args = {}
if args.get("Patch|Game|Component", None) is not None:
file, component = identify(args["Patch|Game|Component"])
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']}")
path = args.get("Patch|Game|Component|url", None)
if path is not None:
if path.startswith("archipelago://"):
args["args"] = (path, *args.get("args", ()))
# add the url arg to the passthrough args
components, text_client_component = handle_uri(path)
if not components:
args["component"] = text_client_component
else:
args['launch_components'] = [text_client_component, *components]
else:
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 {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()
run_gui(args.get("launch_components", None), args.get("args", ()))
if __name__ == '__main__':
init_logging('Launcher')
Utils.freeze_support()
multiprocessing.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())
from worlds.LauncherComponents import processes
for process in processes:
# we await all child processes to close before we tear down the process host
# this makes it feel like each one is its own program, as the Launcher is closed now

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,13 +29,19 @@ 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):
class AdjusterSubWorld(object):
def __init__(self, random):
self.random = random
def __init__(self, sprite_pool):
import random
self.sprite_pool = {1: sprite_pool}
self.per_slot_randoms = {1: random}
self.worlds = {1: self.AdjusterSubWorld(random)}
class ArgumentDefaultsHelpFormatter(argparse.RawTextHelpFormatter):
@@ -43,6 +49,7 @@ class ArgumentDefaultsHelpFormatter(argparse.RawTextHelpFormatter):
def _get_help_string(self, action):
return textwrap.dedent(action.help)
# See argparse.BooleanOptionalAction
class BooleanOptionalActionWithDisable(argparse.Action):
def __init__(self,
@@ -242,16 +249,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 +269,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 +339,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)
@@ -358,10 +365,10 @@ def run_sprite_update():
logging.info("Done updating sprites")
def update_sprites(task, on_finish=None):
def update_sprites(task, on_finish=None, repository_url: str = "https://alttpr.com/sprites"):
resultmessage = ""
successful = True
sprite_dir = user_path("data", "sprites", "alttpr")
sprite_dir = user_path("data", "sprites", "alttp", "remote")
os.makedirs(sprite_dir, exist_ok=True)
ctx = get_cert_none_ssl_context()
@@ -371,11 +378,11 @@ def update_sprites(task, on_finish=None):
on_finish(successful, resultmessage)
try:
task.update_status("Downloading alttpr sprites list")
with urlopen('https://alttpr.com/sprites', context=ctx) as response:
task.update_status("Downloading remote sprites list")
with urlopen(repository_url, context=ctx) as response:
sprites_arr = json.loads(response.read().decode("utf-8"))
except Exception as e:
resultmessage = "Error getting list of alttpr sprites. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e)
resultmessage = "Error getting list of remote sprites. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e)
successful = False
task.queue_event(finished)
return
@@ -383,13 +390,13 @@ def update_sprites(task, on_finish=None):
try:
task.update_status("Determining needed sprites")
current_sprites = [os.path.basename(file) for file in glob(sprite_dir + '/*')]
alttpr_sprites = [(sprite['file'], os.path.basename(urlparse(sprite['file']).path))
remote_sprites = [(sprite['file'], os.path.basename(urlparse(sprite['file']).path))
for sprite in sprites_arr if sprite["author"] != "Nintendo"]
needed_sprites = [(sprite_url, filename) for (sprite_url, filename) in alttpr_sprites if
needed_sprites = [(sprite_url, filename) for (sprite_url, filename) in remote_sprites if
filename not in current_sprites]
alttpr_filenames = [filename for (_, filename) in alttpr_sprites]
obsolete_sprites = [sprite for sprite in current_sprites if sprite not in alttpr_filenames]
remote_filenames = [filename for (_, filename) in remote_sprites]
obsolete_sprites = [sprite for sprite in current_sprites if sprite not in remote_filenames]
except Exception as e:
resultmessage = "Error Determining which sprites to update. Sprites not updated.\n\n%s: %s" % (
type(e).__name__, e)
@@ -441,7 +448,7 @@ def update_sprites(task, on_finish=None):
successful = False
if successful:
resultmessage = "alttpr sprites updated successfully"
resultmessage = "Remote sprites updated successfully"
task.queue_event(finished)
@@ -576,7 +583,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 +603,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 +666,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)
@@ -863,7 +869,7 @@ class SpriteSelector():
def open_custom_sprite_dir(_evt):
open_file(self.custom_sprite_dir)
alttpr_frametitle = Label(self.window, text='ALTTPR Sprites')
remote_frametitle = Label(self.window, text='Remote Sprites')
custom_frametitle = Frame(self.window)
title_text = Label(custom_frametitle, text="Custom Sprites")
@@ -872,8 +878,8 @@ class SpriteSelector():
title_link.pack(side=LEFT)
title_link.bind("<Button-1>", open_custom_sprite_dir)
self.icon_section(alttpr_frametitle, self.alttpr_sprite_dir,
'ALTTPR sprites not found. Click "Update alttpr sprites" to download them.')
self.icon_section(remote_frametitle, self.remote_sprite_dir,
'Remote sprites not found. Click "Update remote sprites" to download them.')
self.icon_section(custom_frametitle, self.custom_sprite_dir,
'Put sprites in the custom sprites folder (see open link above) to have them appear here.')
if not randomOnEvent:
@@ -886,11 +892,18 @@ class SpriteSelector():
button = Button(frame, text="Browse for file...", command=self.browse_for_sprite)
button.pack(side=RIGHT, padx=(5, 0))
button = Button(frame, text="Update alttpr sprites", command=self.update_alttpr_sprites)
button = Button(frame, text="Update remote sprites", command=self.update_remote_sprites)
button.pack(side=RIGHT, padx=(5, 0))
repository_label = Label(frame, text='Sprite Repository:')
self.repository_url = StringVar(frame, "https://alttpr.com/sprites")
repository_entry = Entry(frame, textvariable=self.repository_url)
repository_entry.pack(side=RIGHT, expand=True, fill=BOTH, pady=1)
repository_label.pack(side=RIGHT, expand=False, padx=(0, 5))
button = Button(frame, text="Do not adjust sprite",command=self.use_default_sprite)
button.pack(side=LEFT,padx=(0,5))
button.pack(side=LEFT, padx=(0, 5))
button = Button(frame, text="Default Link sprite", command=self.use_default_link_sprite)
button.pack(side=LEFT, padx=(0, 5))
@@ -1050,7 +1063,7 @@ class SpriteSelector():
for i, button in enumerate(frame.buttons):
button.grid(row=i // self.spritesPerRow, column=i % self.spritesPerRow)
def update_alttpr_sprites(self):
def update_remote_sprites(self):
# need to wrap in try catch. We don't want errors getting the json or downloading the files to break us.
self.window.destroy()
self.parent.update()
@@ -1063,7 +1076,8 @@ class SpriteSelector():
messagebox.showerror("Sprite Updater", resultmessage)
SpriteSelector(self.parent, self.callback, self.adjuster)
BackgroundTaskProgress(self.parent, update_sprites, "Updating Sprites", on_finish)
BackgroundTaskProgress(self.parent, update_sprites, "Updating Sprites",
on_finish, self.repository_url.get())
def browse_for_sprite(self):
sprite = filedialog.askopenfilename(
@@ -1153,12 +1167,13 @@ class SpriteSelector():
os.makedirs(self.custom_sprite_dir)
@property
def alttpr_sprite_dir(self):
return user_path("data", "sprites", "alttpr")
def remote_sprite_dir(self):
return user_path("data", "sprites", "alttp", "remote")
@property
def custom_sprite_dir(self):
return user_path("data", "sprites", "custom")
return user_path("data", "sprites", "alttp", "custom")
def get_image_for_sprite(sprite, gif_only: bool = False):
if not sprite.valid:

View File

@@ -286,16 +286,14 @@ async def gba_sync_task(ctx: MMBN3Context):
except ConnectionRefusedError:
logger.debug("Connection Refused, Trying Again")
ctx.gba_status = CONNECTION_REFUSED_STATUS
await asyncio.sleep(1)
continue
async def run_game(romfile):
options = Utils.get_options().get("mmbn3_options", None)
if options is None:
auto_start = True
else:
auto_start = options.get("rom_start", True)
if auto_start:
from worlds.mmbn3 import MMBN3World
auto_start = MMBN3World.settings.rom_start
if auto_start is True:
import webbrowser
webbrowser.open(romfile)
elif os.path.isfile(auto_start):
@@ -370,7 +368,7 @@ if __name__ == "__main__":
import colorama
colorama.init()
colorama.just_fix_windows_console()
asyncio.run(main())
colorama.deinit()

304
Main.py
View File

@@ -1,19 +1,21 @@
import collections
from collections.abc import Mapping
import concurrent.futures
import logging
import os
import pickle
import tempfile
import time
from typing import Any
import zipfile
import zlib
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 BaseClasses import CollectionState, Item, Location, LocationProgressType, MultiWorld
from Fill import FillError, balance_multiworld_progression, distribute_items_restrictive, flood_items, \
parse_planned_blocks, distribute_planned_blocks, resolve_early_locations_for_planned
from NetUtils import convert_to_base_types
from Options import StartInventoryPool
from Utils import __version__, output_path, version_tuple
from Utils import __version__, output_path, restricted_dumps, version_tuple
from settings import get_settings
from worlds import AutoWorld
from worlds.generic.Rules import exclusion_rules, locality_rules
@@ -21,7 +23,7 @@ from worlds.generic.Rules import exclusion_rules, locality_rules
__all__ = ["main"]
def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = None):
def main(args, seed=None, baked_server_options: dict[str, object] | None = None):
if not baked_server_options:
baked_server_options = get_settings().server_options.as_dict()
assert isinstance(baked_server_options, dict)
@@ -35,16 +37,16 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
logger = logging.getLogger()
multiworld.set_seed(seed, args.race, str(args.outputname) if args.outputname else None)
multiworld.plando_options = args.plando_options
multiworld.plando_items = args.plando_items.copy()
multiworld.plando_texts = args.plando_texts.copy()
multiworld.plando_connections = args.plando_connections.copy()
multiworld.plando_options = args.plando
multiworld.game = args.game.copy()
multiworld.player_name = args.name.copy()
multiworld.sprite = args.sprite.copy()
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)
@@ -52,32 +54,23 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
logger.info(f"Found {len(AutoWorld.AutoWorldRegister.world_types)} World Types:")
longest_name = max(len(text) for text in AutoWorld.AutoWorldRegister.world_types)
max_item = 0
max_location = 0
for cls in AutoWorld.AutoWorldRegister.world_types.values():
if cls.item_id_to_name:
max_item = max(max_item, max(cls.item_id_to_name))
max_location = max(max_location, max(cls.location_id_to_name))
world_classes = AutoWorld.AutoWorldRegister.world_types.values()
item_digits = len(str(max_item))
location_digits = len(str(max_location))
item_count = len(str(max(len(cls.item_names) for cls in AutoWorld.AutoWorldRegister.world_types.values())))
location_count = len(str(max(len(cls.location_names) for cls in AutoWorld.AutoWorldRegister.world_types.values())))
del max_item, max_location
version_count = max(len(cls.world_version.as_simple_string()) for cls in world_classes)
item_count = len(str(max(len(cls.item_names) for cls in world_classes)))
location_count = len(str(max(len(cls.location_names) for cls in world_classes)))
for name, cls in AutoWorld.AutoWorldRegister.world_types.items():
if not cls.hidden and len(cls.item_names) > 0:
logger.info(f" {name:{longest_name}}: {len(cls.item_names):{item_count}} "
f"Items (IDs: {min(cls.item_id_to_name):{item_digits}} - "
f"{max(cls.item_id_to_name):{item_digits}}) | "
f"{len(cls.location_names):{location_count}} "
f"Locations (IDs: {min(cls.location_id_to_name):{location_digits}} - "
f"{max(cls.location_id_to_name):{location_digits}})")
logger.info(f" {name:{longest_name}}: "
f"v{cls.world_version.as_simple_string():{version_count}} | "
f"Items: {len(cls.item_names):{item_count}} | "
f"Locations: {len(cls.location_names):{location_count}}")
del item_digits, location_digits, item_count, location_count
del item_count, location_count
# This assertion method should not be necessary to run if we are not outputting any multidata.
if not args.skip_output:
if not args.skip_output and not args.spoiler_only:
AutoWorld.call_stage(multiworld, "assert_generate")
AutoWorld.call_all(multiworld, "generate_early")
@@ -100,12 +93,21 @@ 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
del early
# items can't be both local and non-local, prefer local
multiworld.worlds[player].options.non_local_items.value -= multiworld.worlds[player].options.local_items.value
multiworld.worlds[player].options.non_local_items.value -= set(multiworld.local_early_items[player])
# Clear non-applicable local and non-local items.
if multiworld.players == 1:
multiworld.worlds[1].options.non_local_items.value = set()
multiworld.worlds[1].options.local_items.value = set()
logger.info('Creating MultiWorld.')
AutoWorld.call_all(multiworld, "create_regions")
@@ -113,155 +115,79 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
AutoWorld.call_all(multiworld, "create_items")
logger.info('Calculating Access Rules.')
for player in multiworld.player_ids:
# items can't be both local and non-local, prefer local
multiworld.worlds[player].options.non_local_items.value -= multiworld.worlds[player].options.local_items.value
multiworld.worlds[player].options.non_local_items.value -= set(multiworld.local_early_items[player])
AutoWorld.call_all(multiworld, "set_rules")
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.
# This function is called so late because worlds might otherwise overwrite item_rules which are how locality works
if multiworld.players > 1:
locality_rules(multiworld)
else:
multiworld.worlds[1].options.non_local_items.value = set()
multiworld.worlds[1].options.local_items.value = set()
multiworld.plando_item_blocks = parse_planned_blocks(multiworld)
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)
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
}
# 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
if target_per_player:
new_itempool: list[Item] = []
# 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
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}")
if any(multiworld.item_links.values()):
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(world.options.item_links for world in multiworld.worlds.values()):
multiworld._all_state = None
logger.info("Running Item Plando.")
distribute_planned(multiworld)
resolve_early_locations_for_planned(multiworld)
distribute_planned_blocks(multiworld, [x for player in multiworld.plando_item_blocks
for x in multiworld.plando_item_blocks[player]])
logger.info('Running Pre Main Fill.')
@@ -272,7 +198,7 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
if multiworld.algorithm == 'flood':
flood_items(multiworld) # different algo, biased towards early game progress items
elif multiworld.algorithm == 'balanced':
distribute_items_restrictive(multiworld)
distribute_items_restrictive(multiworld, get_settings().generator.panic_method)
AutoWorld.call_all(multiworld, 'post_fill')
@@ -291,6 +217,15 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
logger.info(f'Beginning output...')
outfilebase = 'AP_' + multiworld.seed_name
if args.spoiler_only:
if args.spoiler > 1:
logger.info('Calculating playthrough.')
multiworld.spoiler.create_playthrough(create_paths=args.spoiler > 2)
multiworld.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase))
logger.info('Done. Skipped multidata modification. Total time: %s', time.perf_counter() - start)
return multiworld
output = tempfile.TemporaryDirectory()
with output as temp_dir:
output_players = [player for player in multiworld.player_ids if AutoWorld.World.generate_output.__code__
@@ -305,16 +240,19 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
pool.submit(AutoWorld.call_single, multiworld, "generate_output", player, temp_dir))
# collect ER hint info
er_hint_data: Dict[int, Dict[int, str]] = {}
er_hint_data: dict[int, dict[int, str]] = {}
AutoWorld.call_all(multiworld, 'extend_hint_information', er_hint_data)
def write_multidata():
import NetUtils
slot_data = {}
client_versions = {}
games = {}
minimum_versions = {"server": AutoWorld.World.required_server_version, "clients": client_versions}
slot_info = {}
from NetUtils import HintStatus
slot_data: dict[int, Mapping[str, Any]] = {}
client_versions: dict[int, tuple[int, int, int]] = {}
games: dict[int, str] = {}
minimum_versions: NetUtils.MinimumVersions = {
"server": AutoWorld.World.required_server_version, "clients": client_versions
}
slot_info: dict[int, NetUtils.NetworkSlot] = {}
names = [[name for player, name in sorted(multiworld.player_name.items())]]
for slot in multiworld.player_ids:
player_world: AutoWorld.World = multiworld.worlds[slot]
@@ -329,15 +267,17 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
group_members=sorted(group["players"]))
precollected_items = {player: [item.code for item in world_precollected if type(item.code) == int]
for player, world_precollected in multiworld.precollected_items.items()}
precollected_hints = {player: set() for player in range(1, multiworld.players + 1 + len(multiworld.groups))}
precollected_hints: dict[int, set[NetUtils.Hint]] = {
player: set() for player in range(1, multiworld.players + 1 + len(multiworld.groups))
}
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)
@@ -345,34 +285,48 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
for player in multiworld.groups[location.item.player]["players"]:
precollected_hints[player].add(hint)
locations_data: Dict[int, Dict[int, Tuple[int, int, int]]] = {player: {} for player in multiworld.player_ids}
locations_data: dict[int, dict[int, tuple[int, int, int]]] = {player: {} for player in multiworld.player_ids}
for location in multiworld.get_filled_locations():
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 = {
game_world.game: worlds.network_data_package["games"][game_world.game]
for game_world in multiworld.worlds.values()
}
data_package["Archipelago"] = worlds.network_data_package["games"]["Archipelago"]
checks_in_area: Dict[int, Dict[str, Union[int, List[int]]]] = {}
checks_in_area: dict[int, dict[str, int | list[int]]] = {}
multidata = {
# get spheres -> filter address==None -> skip empty
spheres: list[dict[int, set[int]]] = []
for sphere in multiworld.get_sendable_spheres():
current_sphere: dict[int, set[int]] = collections.defaultdict(set)
for sphere_location in sphere:
current_sphere[sphere_location.player].add(sphere_location.address)
if current_sphere:
spheres.append(dict(current_sphere))
multidata: NetUtils.MultiData = {
"slot_data": slot_data,
"slot_info": slot_info,
"connect_names": {name: (0, player) for player, name in multiworld.player_name.items()},
@@ -382,24 +336,30 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
"er_hint_data": er_hint_data,
"precollected_items": precollected_items,
"precollected_hints": precollected_hints,
"version": tuple(version_tuple),
"version": (version_tuple.major, version_tuple.minor, version_tuple.build),
"tags": ["AP"],
"minimum_versions": minimum_versions,
"seed_name": multiworld.seed_name,
"spheres": spheres,
"datapackage": data_package,
"race_mode": int(multiworld.is_race),
}
# TODO: change to `"version": version_tuple` after getting better serialization
AutoWorld.call_all(multiworld, "modify_multidata", multidata)
multidata = zlib.compress(pickle.dumps(multidata), 9)
for key in ("slot_data", "er_hint_data"):
multidata[key] = convert_to_base_types(multidata[key])
serialized_multidata = zlib.compress(restricted_dumps(multidata), 9)
with open(os.path.join(temp_dir, f'{outfilebase}.archipelago'), 'wb') as f:
f.write(bytes([3])) # version of format
f.write(multidata)
f.write(serialized_multidata)
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

@@ -1,344 +0,0 @@
import argparse
import json
import os
import sys
import re
import atexit
import shutil
from subprocess import Popen
from shutil import copyfile
from time import strftime
import logging
import requests
import Utils
from Utils import is_windows
atexit.register(input, "Press enter to exit.")
# 1 or more digits followed by m or g, then optional b
max_heap_re = re.compile(r"^\d+[mMgG][bB]?$")
def prompt_yes_no(prompt):
yes_inputs = {'yes', 'ye', 'y'}
no_inputs = {'no', 'n'}
while True:
choice = input(prompt + " [y/n] ").lower()
if choice in yes_inputs:
return True
elif choice in no_inputs:
return False
else:
print('Please respond with "y" or "n".')
def find_ap_randomizer_jar(forge_dir):
"""Create mods folder if needed; find AP randomizer jar; return None if not found."""
mods_dir = os.path.join(forge_dir, 'mods')
if os.path.isdir(mods_dir):
for entry in os.scandir(mods_dir):
if entry.name.startswith("aprandomizer") and entry.name.endswith(".jar"):
logging.info(f"Found AP randomizer mod: {entry.name}")
return entry.name
return None
else:
os.mkdir(mods_dir)
logging.info(f"Created mods folder in {forge_dir}")
return None
def replace_apmc_files(forge_dir, apmc_file):
"""Create APData folder if needed; clean .apmc files from APData; copy given .apmc into directory."""
if apmc_file is None:
return
apdata_dir = os.path.join(forge_dir, 'APData')
copy_apmc = True
if not os.path.isdir(apdata_dir):
os.mkdir(apdata_dir)
logging.info(f"Created APData folder in {forge_dir}")
for entry in os.scandir(apdata_dir):
if entry.name.endswith(".apmc") and entry.is_file():
if not os.path.samefile(apmc_file, entry.path):
os.remove(entry.path)
logging.info(f"Removed {entry.name} in {apdata_dir}")
else: # apmc already in apdata
copy_apmc = False
if copy_apmc:
copyfile(apmc_file, os.path.join(apdata_dir, os.path.basename(apmc_file)))
logging.info(f"Copied {os.path.basename(apmc_file)} to {apdata_dir}")
def read_apmc_file(apmc_file):
from base64 import b64decode
with open(apmc_file, 'r') as f:
return json.loads(b64decode(f.read()))
def update_mod(forge_dir, url: str):
"""Check mod version, download new mod from GitHub releases page if needed. """
ap_randomizer = find_ap_randomizer_jar(forge_dir)
os.path.basename(url)
if ap_randomizer is not None:
logging.info(f"Your current mod is {ap_randomizer}.")
else:
logging.info(f"You do not have the AP randomizer mod installed.")
if ap_randomizer != os.path.basename(url):
logging.info(f"A new release of the Minecraft AP randomizer mod was found: "
f"{os.path.basename(url)}")
if prompt_yes_no("Would you like to update?"):
old_ap_mod = os.path.join(forge_dir, 'mods', ap_randomizer) if ap_randomizer is not None else None
new_ap_mod = os.path.join(forge_dir, 'mods', os.path.basename(url))
logging.info("Downloading AP randomizer mod. This may take a moment...")
apmod_resp = requests.get(url)
if apmod_resp.status_code == 200:
with open(new_ap_mod, 'wb') as f:
f.write(apmod_resp.content)
logging.info(f"Wrote new mod file to {new_ap_mod}")
if old_ap_mod is not None:
os.remove(old_ap_mod)
logging.info(f"Removed old mod file from {old_ap_mod}")
else:
logging.error(f"Error retrieving the randomizer mod (status code {apmod_resp.status_code}).")
logging.error(f"Please report this issue on the Archipelago Discord server.")
sys.exit(1)
def check_eula(forge_dir):
"""Check if the EULA is agreed to, and prompt the user to read and agree if necessary."""
eula_path = os.path.join(forge_dir, "eula.txt")
if not os.path.isfile(eula_path):
# Create eula.txt
with open(eula_path, 'w') as f:
f.write("#By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).\n")
f.write(f"#{strftime('%a %b %d %X %Z %Y')}\n")
f.write("eula=false\n")
with open(eula_path, 'r+') as f:
text = f.read()
if 'false' in text:
# Prompt user to agree to the EULA
logging.info("You need to agree to the Minecraft EULA in order to run the server.")
logging.info("The EULA can be found at https://account.mojang.com/documents/minecraft_eula")
if prompt_yes_no("Do you agree to the EULA?"):
f.seek(0)
f.write(text.replace('false', 'true'))
f.truncate()
logging.info(f"Set {eula_path} to true")
else:
sys.exit(0)
def find_jdk_dir(version: str) -> str:
"""get the specified versions jdk directory"""
for entry in os.listdir():
if os.path.isdir(entry) and entry.startswith(f"jdk{version}"):
return os.path.abspath(entry)
def find_jdk(version: str) -> str:
"""get the java exe location"""
if is_windows:
jdk = find_jdk_dir(version)
jdk_exe = os.path.join(jdk, "bin", "java.exe")
if os.path.isfile(jdk_exe):
return jdk_exe
else:
jdk_exe = shutil.which(options["minecraft_options"].get("java", "java"))
if not jdk_exe:
raise Exception("Could not find Java. Is Java installed on the system?")
return jdk_exe
def download_java(java: str):
"""Download Corretto (Amazon JDK)"""
jdk = find_jdk_dir(java)
if jdk is not None:
print(f"Removing old JDK...")
from shutil import rmtree
rmtree(jdk)
print(f"Downloading Java...")
jdk_url = f"https://corretto.aws/downloads/latest/amazon-corretto-{java}-x64-windows-jdk.zip"
resp = requests.get(jdk_url)
if resp.status_code == 200: # OK
print(f"Extracting...")
import zipfile
from io import BytesIO
with zipfile.ZipFile(BytesIO(resp.content)) as zf:
zf.extractall()
else:
print(f"Error downloading Java (status code {resp.status_code}).")
print(f"If this was not expected, please report this issue on the Archipelago Discord server.")
if not prompt_yes_no("Continue anyways?"):
sys.exit(0)
def install_forge(directory: str, forge_version: str, java_version: str):
"""download and install forge"""
java_exe = find_jdk(java_version)
if java_exe is not None:
print(f"Downloading Forge {forge_version}...")
forge_url = f"https://maven.minecraftforge.net/net/minecraftforge/forge/{forge_version}/forge-{forge_version}-installer.jar"
resp = requests.get(forge_url)
if resp.status_code == 200: # OK
forge_install_jar = os.path.join(directory, "forge_install.jar")
if not os.path.exists(directory):
os.mkdir(directory)
with open(forge_install_jar, 'wb') as f:
f.write(resp.content)
print(f"Installing Forge...")
install_process = Popen([java_exe, "-jar", forge_install_jar, "--installServer", directory])
install_process.wait()
os.remove(forge_install_jar)
def run_forge_server(forge_dir: str, java_version: str, heap_arg: str) -> Popen:
"""Run the Forge server."""
java_exe = find_jdk(java_version)
if not os.path.isfile(java_exe):
java_exe = "java" # try to fall back on java in the PATH
heap_arg = max_heap_re.match(heap_arg).group()
if heap_arg[-1] in ['b', 'B']:
heap_arg = heap_arg[:-1]
heap_arg = "-Xmx" + heap_arg
os_args = "win_args.txt" if is_windows else "unix_args.txt"
args_file = os.path.join(forge_dir, "libraries", "net", "minecraftforge", "forge", forge_version, os_args)
forge_args = []
with open(args_file) as argfile:
for line in argfile:
forge_args.extend(line.strip().split(" "))
args = [java_exe, heap_arg, *forge_args, "-nogui"]
logging.info(f"Running Forge server: {args}")
os.chdir(forge_dir)
return Popen(args)
def get_minecraft_versions(version, release_channel="release"):
version_file_endpoint = "https://raw.githubusercontent.com/KonoTyran/Minecraft_AP_Randomizer/master/versions/minecraft_versions.json"
resp = requests.get(version_file_endpoint)
local = False
if resp.status_code == 200: # OK
try:
data = resp.json()
except requests.exceptions.JSONDecodeError:
logging.warning(f"Unable to fetch version update file, using local version. (status code {resp.status_code}).")
local = True
else:
logging.warning(f"Unable to fetch version update file, using local version. (status code {resp.status_code}).")
local = True
if local:
with open(Utils.user_path("minecraft_versions.json"), 'r') as f:
data = json.load(f)
else:
with open(Utils.user_path("minecraft_versions.json"), 'w') as f:
json.dump(data, f)
try:
if version:
return next(filter(lambda entry: entry["version"] == version, data[release_channel]))
else:
return resp.json()[release_channel][0]
except (StopIteration, KeyError):
logging.error(f"No compatible mod version found for client version {version} on \"{release_channel}\" channel.")
if release_channel != "release":
logging.error("Consider switching \"release_channel\" to \"release\" in your Host.yaml file")
else:
logging.error("No suitable mod found on the \"release\" channel. Please Contact us on discord to report this error.")
sys.exit(0)
def is_correct_forge(forge_dir) -> bool:
if os.path.isdir(os.path.join(forge_dir, "libraries", "net", "minecraftforge", "forge", forge_version)):
return True
return False
if __name__ == '__main__':
Utils.init_logging("MinecraftClient")
parser = argparse.ArgumentParser()
parser.add_argument("apmc_file", default=None, nargs='?', help="Path to an Archipelago Minecraft data file (.apmc)")
parser.add_argument('--install', '-i', dest='install', default=False, action='store_true',
help="Download and install Java and the Forge server. Does not launch the client afterwards.")
parser.add_argument('--release_channel', '-r', dest="channel", type=str, action='store',
help="Specify release channel to use.")
parser.add_argument('--java', '-j', metavar='17', dest='java', type=str, default=False, action='store',
help="specify java version.")
parser.add_argument('--forge', '-f', metavar='1.18.2-40.1.0', dest='forge', type=str, default=False, action='store',
help="specify forge version. (Minecraft Version-Forge Version)")
parser.add_argument('--version', '-v', metavar='9', dest='data_version', type=int, action='store',
help="specify Mod data version to download.")
args = parser.parse_args()
apmc_file = os.path.abspath(args.apmc_file) if args.apmc_file else None
# Change to executable's working directory
os.chdir(os.path.abspath(os.path.dirname(sys.argv[0])))
options = Utils.get_options()
channel = args.channel or options["minecraft_options"]["release_channel"]
apmc_data = None
data_version = args.data_version or None
if apmc_file is None and not args.install:
apmc_file = Utils.open_filename('Select APMC file', (('APMC File', ('.apmc',)),))
if apmc_file is not None and data_version is None:
apmc_data = read_apmc_file(apmc_file)
data_version = apmc_data.get('client_version', '')
versions = get_minecraft_versions(data_version, channel)
forge_dir = options["minecraft_options"]["forge_directory"]
max_heap = options["minecraft_options"]["max_heap_size"]
forge_version = args.forge or versions["forge"]
java_version = args.java or versions["java"]
mod_url = versions["url"]
java_dir = find_jdk_dir(java_version)
if args.install:
if is_windows:
print("Installing Java")
download_java(java_version)
if not is_correct_forge(forge_dir):
print("Installing Minecraft Forge")
install_forge(forge_dir, forge_version, java_version)
else:
print("Correct Forge version already found, skipping install.")
sys.exit(0)
if apmc_data is None:
raise FileNotFoundError(f"APMC file does not exist or is inaccessible at the given location ({apmc_file})")
if is_windows:
if java_dir is None or not os.path.isdir(java_dir):
if prompt_yes_no("Did not find java directory. Download and install java now?"):
download_java(java_version)
java_dir = find_jdk_dir(java_version)
if java_dir is None or not os.path.isdir(java_dir):
raise NotADirectoryError(f"Path {java_dir} does not exist or could not be accessed.")
if not is_correct_forge(forge_dir):
if prompt_yes_no(f"Did not find forge version {forge_version} download and install it now?"):
install_forge(forge_dir, forge_version, java_version)
if not os.path.isdir(forge_dir):
raise NotADirectoryError(f"Path {forge_dir} does not exist or could not be accessed.")
if not max_heap_re.match(max_heap):
raise Exception(f"Max heap size {max_heap} in incorrect format. Use a number followed by M or G, e.g. 512M or 2G.")
update_mod(forge_dir, mod_url)
replace_apmc_files(forge_dir, apmc_file)
check_eula(forge_dir)
server_process = run_forge_server(forge_dir, java_version, max_heap)
server_process.wait()

View File

@@ -5,11 +5,23 @@ 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 not (3, 11, 9) <= sys.version_info < (3, 14, 0):
# 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.11.9 through 3.13.x is supported.")
elif sys.platform in ("win32", "darwin") and sys.version_info < (3, 11, 13):
# 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 not (3, 11, 0) <= sys.version_info < (3, 14, 0):
# 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.11.0 through 3.13.x 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())
_skip_update = bool(
getattr(sys, "frozen", False) or
multiprocessing.parent_process() or
os.environ.get("SKIP_REQUIREMENTS_UPDATE", "").lower() in ("1", "true", "yes")
)
update_ran = _skip_update
@@ -63,11 +75,11 @@ def update_command():
def install_pkg_resources(yes=False):
try:
import pkg_resources # noqa: F401
except ImportError:
except (AttributeError, ImportError):
check_pip()
if not yes:
confirm("pkg_resources not found, press enter to install it")
subprocess.call([sys.executable, "-m", "pip", "install", "--upgrade", "setuptools"])
subprocess.call([sys.executable, "-m", "pip", "install", "--upgrade", "setuptools>=75,<81"])
def update(yes: bool = False, force: bool = False) -> None:
@@ -75,13 +87,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)

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,25 @@
from __future__ import annotations
from collections.abc import Mapping, Sequence
import typing
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_UNSPECIFIED = 0
HINT_NO_PRIORITY = 10
HINT_AVOID = 20
HINT_PRIORITY = 30
HINT_FOUND = 40
class JSONMessagePart(typing.TypedDict, total=False):
text: str
# optional
@@ -19,6 +29,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):
@@ -72,13 +84,14 @@ class NetworkSlot(typing.NamedTuple):
name: str
game: str
type: SlotType
group_members: typing.Union[typing.List[int], typing.Tuple] = () # only populated if type == group
group_members: Sequence[int] = () # only populated if type == group
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
@@ -94,6 +107,27 @@ def _scan_for_TypedTuples(obj: typing.Any) -> typing.Any:
return obj
_base_types = str | int | bool | float | None | tuple["_base_types", ...] | dict["_base_types", "base_types"]
def convert_to_base_types(obj: typing.Any) -> _base_types:
if isinstance(obj, (tuple, list, set, frozenset)):
return tuple(convert_to_base_types(o) for o in obj)
elif isinstance(obj, dict):
return {convert_to_base_types(key): convert_to_base_types(value) for key, value in obj.items()}
elif obj is None or type(obj) in (str, int, float, bool):
return obj
# unwrap simple types to their base, such as StrEnum
elif isinstance(obj, str):
return str(obj)
elif isinstance(obj, int):
return int(obj)
elif isinstance(obj, float):
return float(obj)
else:
raise Exception(f"Cannot handle {type(obj)}")
_encode = JSONEncoder(
ensure_ascii=False,
check_circular=False,
@@ -140,7 +174,9 @@ decode = JSONDecoder(object_hook=_object_hook).decode
class Endpoint:
socket: websockets.WebSocketServerProtocol
__slots__ = ("socket",)
socket: "ServerConnection"
def __init__(self, socket):
self.socket = socket
@@ -183,6 +219,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):
@@ -198,7 +235,8 @@ class JSONtoTextParser(metaclass=HandlerMeta):
"slateblue": "6D8BE8",
"plum": "AF99EF",
"salmon": "FA8072",
"white": "FFFFFF"
"white": "FFFFFF",
"orange": "FF7700",
}
def __init__(self, ctx):
@@ -222,7 +260,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)
@@ -247,7 +285,7 @@ class JSONtoTextParser(metaclass=HandlerMeta):
def _handle_item_id(self, node: JSONMessagePart):
item_id = int(node["text"])
node["text"] = self.ctx.item_names[item_id]
node["text"] = self.ctx.item_names.lookup_in_slot(item_id, node["player"])
return self._handle_item_name(node)
def _handle_location_name(self, node: JSONMessagePart):
@@ -255,14 +293,18 @@ class JSONtoTextParser(metaclass=HandlerMeta):
return self._handle_color(node)
def _handle_location_id(self, node: JSONMessagePart):
item_id = int(node["text"])
node["text"] = self.ctx.location_names[item_id]
location_id = int(node["text"])
node["text"] = self.ctx.location_names.lookup_in_slot(location_id, node["player"])
return self._handle_location_name(node)
def _handle_entrance_name(self, node: JSONMessagePart):
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):
@@ -271,7 +313,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):
@@ -294,6 +337,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
@@ -302,14 +366,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):
@@ -331,10 +402,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,
@@ -380,6 +448,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
@@ -396,12 +466,48 @@ 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])
class MinimumVersions(typing.TypedDict):
server: tuple[int, int, int]
clients: dict[int, tuple[int, int, int]]
class GamesPackage(typing.TypedDict, total=False):
item_name_groups: dict[str, list[str]]
item_name_to_id: dict[str, int]
location_name_groups: dict[str, list[str]]
location_name_to_id: dict[str, int]
checksum: str
class DataPackage(typing.TypedDict):
games: dict[str, GamesPackage]
class MultiData(typing.TypedDict):
slot_data: dict[int, Mapping[str, typing.Any]]
slot_info: dict[int, NetworkSlot]
connect_names: dict[str, tuple[int, int]]
locations: dict[int, dict[int, tuple[int, int, int]]]
checks_in_area: dict[int, dict[str, int | list[int]]]
server_options: dict[str, object]
er_hint_data: dict[int, dict[int, str]]
precollected_items: dict[int, list[int]]
precollected_hints: dict[int, set[Hint]]
version: tuple[int, int, int]
tags: list[str]
minimum_versions: MinimumVersions
seed_name: str
spheres: list[dict[int, set[int]]]
datapackage: dict[str, GamesPackage]
race_mode: int
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

@@ -12,6 +12,7 @@ from CommonClient import CommonContext, server_loop, gui_enabled, \
import Utils
from Utils import async_start
from worlds import network_data_package
from worlds.oot import OOTWorld
from worlds.oot.Rom import Rom, compress_rom_file
from worlds.oot.N64Patch import apply_patch_file
from worlds.oot.Utils import data_path
@@ -276,11 +277,12 @@ async def n64_sync_task(ctx: OoTContext):
except ConnectionRefusedError:
logger.debug("Connection Refused, Trying Again")
ctx.n64_status = CONNECTION_REFUSED_STATUS
await asyncio.sleep(1)
continue
async def run_game(romfile):
auto_start = Utils.get_options()["oot_options"].get("rom_start", True)
auto_start = OOTWorld.settings.rom_start
if auto_start is True:
import webbrowser
webbrowser.open(romfile)
@@ -295,7 +297,7 @@ async def patch_and_run_game(apz5_file):
decomp_path = base_name + '-decomp.z64'
comp_path = base_name + '.z64'
# Load vanilla ROM, patch file, compress ROM
rom_file_name = Utils.get_options()["oot_options"]["rom_file"]
rom_file_name = OOTWorld.settings.rom_file
rom = Rom(rom_file_name)
sub_file = None
@@ -346,7 +348,7 @@ if __name__ == '__main__':
import colorama
colorama.init()
colorama.just_fix_windows_console()
asyncio.run(main())
colorama.deinit()

1004
Options.py

File diff suppressed because it is too large Load Diff

696
OptionsCreator.py Normal file
View File

@@ -0,0 +1,696 @@
if __name__ == "__main__":
import ModuleUpdate
ModuleUpdate.update()
from kvui import (ThemedApp, ScrollBox, MainLayout, ContainerLayout, dp, Widget, MDBoxLayout, TooltipLabel, MDLabel,
ToggleButton, MarkupDropdown, ResizableTextField)
from kivy.clock import Clock
from kivy.uix.behaviors.button import ButtonBehavior
from kivymd.uix.behaviors import RotateBehavior
from kivymd.uix.anchorlayout import MDAnchorLayout
from kivymd.uix.expansionpanel import MDExpansionPanel, MDExpansionPanelContent, MDExpansionPanelHeader
from kivymd.uix.list import MDListItem, MDListItemTrailingIcon, MDListItemSupportingText
from kivymd.uix.slider import MDSlider
from kivymd.uix.snackbar import MDSnackbar, MDSnackbarText
from kivymd.uix.menu import MDDropdownMenu
from kivymd.uix.button import MDButton, MDButtonText, MDIconButton
from kivymd.uix.dialog import MDDialog
from kivy.core.text.markup import MarkupLabel
from kivy.utils import escape_markup
from kivy.lang.builder import Builder
from kivy.properties import ObjectProperty
from textwrap import dedent
from copy import deepcopy
import Utils
import typing
import webbrowser
import re
from urllib.parse import urlparse
from worlds.AutoWorld import AutoWorldRegister, World
from Options import (Option, Toggle, TextChoice, Choice, FreeText, NamedRange, Range, OptionSet, OptionList, Removed,
OptionCounter, Visibility)
def validate_url(x):
try:
result = urlparse(x)
return all([result.scheme, result.netloc])
except AttributeError:
return False
def filter_tooltip(tooltip):
if tooltip is None:
tooltip = "No tooltip available."
tooltip = dedent(tooltip).strip().replace("\n", "<br>").replace("&", "&amp;") \
.replace("[", "&bl;").replace("]", "&br;")
tooltip = re.sub(r"\*\*(.+?)\*\*", r"[b]\g<1>[/b]", tooltip)
tooltip = re.sub(r"\*(.+?)\*", r"[i]\g<1>[/i]", tooltip)
return escape_markup(tooltip)
def option_can_be_randomized(option: typing.Type[Option]):
# most options can be randomized, so we should just check for those that cannot
if not option.supports_weighting:
return False
elif issubclass(option, FreeText) and not issubclass(option, TextChoice):
return False
return True
def check_random(value: typing.Any):
if not isinstance(value, str):
return value # cannot be random if evaluated
if value.startswith("random-"):
return "random"
return value
class TrailingPressedIconButton(ButtonBehavior, RotateBehavior, MDListItemTrailingIcon):
pass
class WorldButton(ToggleButton):
world_cls: typing.Type[World]
class VisualRange(MDBoxLayout):
option: typing.Type[Range]
name: str
tag: MDLabel = ObjectProperty(None)
slider: MDSlider = ObjectProperty(None)
def __init__(self, *args, option: typing.Type[Range], name: str, **kwargs):
self.option = option
self.name = name
super().__init__(*args, **kwargs)
def update_points(*update_args):
pass
self.slider._update_points = update_points
class VisualChoice(MDButton):
option: typing.Type[Choice]
name: str
text: MDButtonText = ObjectProperty(None)
def __init__(self, *args, option: typing.Type[Choice], name: str, **kwargs):
self.option = option
self.name = name
super().__init__(*args, **kwargs)
class VisualNamedRange(MDBoxLayout):
option: typing.Type[NamedRange]
name: str
range: VisualRange = ObjectProperty(None)
choice: MDButton = ObjectProperty(None)
def __init__(self, *args, option: typing.Type[NamedRange], name: str, range_widget: VisualRange, **kwargs):
self.option = option
self.name = name
super().__init__(*args, **kwargs)
self.range = range_widget
self.add_widget(self.range)
class VisualFreeText(ResizableTextField):
option: typing.Type[FreeText] | typing.Type[TextChoice]
name: str
def __init__(self, *args, option: typing.Type[FreeText] | typing.Type[TextChoice], name: str, **kwargs):
self.option = option
self.name = name
super().__init__(*args, **kwargs)
class VisualTextChoice(MDBoxLayout):
option: typing.Type[TextChoice]
name: str
choice: VisualChoice = ObjectProperty(None)
text: VisualFreeText = ObjectProperty(None)
def __init__(self, *args, option: typing.Type[TextChoice], name: str, choice: VisualChoice,
text: VisualFreeText, **kwargs):
self.option = option
self.name = name
super(MDBoxLayout, self).__init__(*args, **kwargs)
self.choice = choice
self.text = text
self.add_widget(self.choice)
self.add_widget(self.text)
class VisualToggle(MDBoxLayout):
button: MDIconButton = ObjectProperty(None)
option: typing.Type[Toggle]
name: str
def __init__(self, *args, option: typing.Type[Toggle], name: str, **kwargs):
self.option = option
self.name = name
super().__init__(*args, **kwargs)
class CounterItemValue(ResizableTextField):
pat = re.compile('[^0-9]')
def insert_text(self, substring, from_undo=False):
return super().insert_text(re.sub(self.pat, "", substring), from_undo=from_undo)
class VisualListSetCounter(MDDialog):
button: MDIconButton = ObjectProperty(None)
option: typing.Type[OptionSet] | typing.Type[OptionList] | typing.Type[OptionCounter]
scrollbox: ScrollBox = ObjectProperty(None)
add: MDIconButton = ObjectProperty(None)
save: MDButton = ObjectProperty(None)
input: ResizableTextField = ObjectProperty(None)
dropdown: MDDropdownMenu
valid_keys: typing.Iterable[str]
def __init__(self, *args, option: typing.Type[OptionSet] | typing.Type[OptionList],
name: str, valid_keys: typing.Iterable[str], **kwargs):
self.option = option
self.name = name
self.valid_keys = valid_keys
super().__init__(*args, **kwargs)
self.dropdown = MarkupDropdown(caller=self.input, border_margin=dp(2),
width=self.input.width, position="bottom")
self.input.bind(text=self.on_text)
self.input.bind(on_text_validate=self.validate_add)
def validate_add(self, instance):
if self.valid_keys:
if self.input.text not in self.valid_keys:
MDSnackbar(MDSnackbarText(text="Item must be a valid key for this option."), y=dp(24),
pos_hint={"center_x": 0.5}, size_hint_x=0.5).open()
return
if not issubclass(self.option, OptionList):
if any(self.input.text == child.text.text for child in self.scrollbox.layout.children):
MDSnackbar(MDSnackbarText(text="This value is already in the set."), y=dp(24),
pos_hint={"center_x": 0.5}, size_hint_x=0.5).open()
return
self.add_set_item(self.input.text)
self.input.set_text(self.input, "")
def remove_item(self, button: MDIconButton):
list_item = button.parent
self.scrollbox.layout.remove_widget(list_item)
def add_set_item(self, key: str, value: int | None = None):
text = MDListItemSupportingText(text=key, id="value")
if issubclass(self.option, OptionCounter):
value_txt = CounterItemValue(text=str(value) if value else "1")
item = MDListItem(text,
value_txt,
MDIconButton(icon="minus", on_release=self.remove_item), focus_behavior=False)
item.value = value_txt
else:
item = MDListItem(text, MDIconButton(icon="minus", on_release=self.remove_item), focus_behavior=False)
item.text = text
self.scrollbox.layout.add_widget(item)
def on_text(self, instance, value):
if not self.valid_keys:
return
if len(value) >= 3:
self.dropdown.items.clear()
def on_press(txt):
split_text = MarkupLabel(text=txt, markup=True).markup
self.input.set_text(self.input, "".join(text_frag for text_frag in split_text
if not text_frag.startswith("[")))
self.input.focus = True
self.dropdown.dismiss()
lowered = value.lower()
for item_name in self.valid_keys:
try:
index = item_name.lower().index(lowered)
except ValueError:
pass # substring not found
else:
text = escape_markup(item_name)
text = text[:index] + "[b]" + text[index:index + len(value)] + "[/b]" + text[index + len(value):]
self.dropdown.items.append({
"text": text,
"on_release": lambda txt=text: on_press(txt),
"markup": True
})
if not self.dropdown.parent:
self.dropdown.open()
else:
self.dropdown.dismiss()
class OptionsCreator(ThemedApp):
base_title: str = "Archipelago Options Creator"
container: ContainerLayout
main_layout: MainLayout
scrollbox: ScrollBox
main_panel: MainLayout
player_options: MainLayout
option_layout: MainLayout
name_input: ResizableTextField
game_label: MDLabel
current_game: str
options: typing.Dict[str, typing.Any]
def __init__(self):
self.title = self.base_title + " " + Utils.__version__
self.icon = r"data/icon.png"
self.current_game = ""
self.options = {}
super().__init__()
@staticmethod
def show_result_snack(text: str) -> None:
MDSnackbar(MDSnackbarText(text=text), y=dp(24), pos_hint={"center_x": 0.5}, size_hint_x=0.5).open()
def on_export_result(self, text: str | None) -> None:
self.container.disabled = False
if text is not None:
Clock.schedule_once(lambda _: self.show_result_snack(text), 0)
def export_options_background(self, options: dict[str, typing.Any]) -> None:
try:
file_name = Utils.save_filename("Export Options File As...", [("YAML", [".yaml"])],
Utils.get_file_safe_name(f"{self.name_input.text}.yaml"))
except Exception:
self.on_export_result("Could not open dialog. Already open?")
raise
if not file_name:
self.on_export_result(None) # No file selected. No need to show a message for this.
return
try:
with open(file_name, 'w') as f:
f.write(Utils.dump(options, sort_keys=False))
f.close()
self.on_export_result("File saved successfully.")
except Exception:
self.on_export_result("Could not save file.")
raise
def export_options(self, button: Widget) -> None:
if 0 < len(self.name_input.text) < 17 and self.current_game:
import threading
options = {
"name": self.name_input.text,
"description": f"YAML generated by Archipelago {Utils.__version__}.",
"game": self.current_game,
self.current_game: {k: check_random(v) for k, v in self.options.items()}
}
threading.Thread(target=self.export_options_background, args=(options,), daemon=True).start()
self.container.disabled = True
elif not self.name_input.text:
self.show_result_snack("Name must not be empty.")
elif not self.current_game:
self.show_result_snack("You must select a game to play.")
else:
self.show_result_snack("Name cannot be longer than 16 characters.")
def create_range(self, option: typing.Type[Range], name: str):
def update_text(range_box: VisualRange):
self.options[name] = int(range_box.slider.value)
range_box.tag.text = str(int(range_box.slider.value))
return
box = VisualRange(option=option, name=name)
box.slider.bind(on_touch_move=lambda _, _1: update_text(box))
self.options[name] = option.default
return box
def create_named_range(self, option: typing.Type[NamedRange], name: str):
def set_to_custom(range_box: VisualNamedRange):
if (not self.options[name] == range_box.range.slider.value) \
and (not self.options[name] in option.special_range_names or
range_box.range.slider.value != option.special_range_names[self.options[name]]):
# we should validate the touch here,
# but this is much cheaper
self.options[name] = int(range_box.range.slider.value)
range_box.range.tag.text = str(int(range_box.range.slider.value))
set_button_text(range_box.choice, "Custom")
def set_button_text(button: MDButton, text: str):
button.text.text = text
def set_value(text: str, range_box: VisualNamedRange):
range_box.range.slider.value = min(max(option.special_range_names[text.lower()], option.range_start),
option.range_end)
range_box.range.tag.text = str(int(range_box.range.slider.value))
set_button_text(range_box.choice, text)
self.options[name] = text.lower()
range_box.range.slider.dropdown.dismiss()
def open_dropdown(button):
# for some reason this fixes an issue causing some to not open
box.range.slider.dropdown.open()
box = VisualNamedRange(option=option, name=name, range_widget=self.create_range(option, name))
if option.default in option.special_range_names:
# value can get mismatched in this case
box.range.slider.value = min(max(option.special_range_names[option.default], option.range_start),
option.range_end)
box.range.tag.text = str(int(box.range.slider.value))
box.range.slider.bind(on_touch_move=lambda _, _2: set_to_custom(box))
items = [
{
"text": choice.title(),
"on_release": lambda text=choice.title(): set_value(text, box)
}
for choice in option.special_range_names
]
box.range.slider.dropdown = MDDropdownMenu(caller=box.choice, items=items)
box.choice.bind(on_release=open_dropdown)
self.options[name] = option.default
return box
def create_free_text(self, option: typing.Type[FreeText] | typing.Type[TextChoice], name: str):
text = VisualFreeText(option=option, name=name)
def set_value(instance):
self.options[name] = instance.text
text.bind(on_text_validate=set_value)
return text
def create_choice(self, option: typing.Type[Choice], name: str):
def set_button_text(button: VisualChoice, text: str):
button.text.text = text
def set_value(text, value):
set_button_text(main_button, text)
self.options[name] = value
dropdown.dismiss()
def open_dropdown(button):
# for some reason this fixes an issue causing some to not open
dropdown.open()
default_string = isinstance(option.default, str)
main_button = VisualChoice(option=option, name=name)
main_button.bind(on_release=open_dropdown)
items = [
{
"text": option.get_option_name(choice),
"on_release": lambda val=choice: set_value(option.get_option_name(val), option.name_lookup[val])
}
for choice in option.name_lookup
]
dropdown = MDDropdownMenu(caller=main_button, items=items)
self.options[name] = option.name_lookup[option.default] if not default_string else option.default
return main_button
def create_text_choice(self, option: typing.Type[TextChoice], name: str):
def set_button_text(button: MDButton, text: str):
for child in button.children:
if isinstance(child, MDButtonText):
child.text = text
box = VisualTextChoice(option=option, name=name, choice=self.create_choice(option, name),
text=self.create_free_text(option, name))
def set_value(instance):
set_button_text(box.choice, "Custom")
self.options[name] = instance.text
box.text.bind(on_text_validate=set_value)
return box
def create_toggle(self, option: typing.Type[Toggle], name: str) -> Widget:
def set_value(instance: MDIconButton):
if instance.icon == "checkbox-outline":
instance.icon = "checkbox-blank-outline"
else:
instance.icon = "checkbox-outline"
self.options[name] = bool(not self.options[name])
self.options[name] = bool(option.default)
checkbox = VisualToggle(option=option, name=name)
checkbox.button.bind(on_release=set_value)
return checkbox
def create_popup(self, option: typing.Type[OptionList] | typing.Type[OptionSet] | typing.Type[OptionCounter],
name: str, world: typing.Type[World]):
valid_keys = sorted(option.valid_keys)
if option.verify_item_name:
valid_keys += list(world.item_name_to_id.keys())
if option.verify_location_name:
valid_keys += list(world.location_name_to_id.keys())
if not issubclass(option, OptionCounter):
def apply_changes(button):
self.options[name].clear()
for list_item in dialog.scrollbox.layout.children:
self.options[name].append(getattr(list_item.text, "text"))
dialog.dismiss()
else:
def apply_changes(button):
self.options[name].clear()
for list_item in dialog.scrollbox.layout.children:
self.options[name][getattr(list_item.text, "text")] = int(getattr(list_item.value, "text"))
dialog.dismiss()
dialog = VisualListSetCounter(option=option, name=name, valid_keys=valid_keys)
dialog.ids.container.spacing = dp(30)
dialog.scrollbox.layout.theme_bg_color = "Custom"
dialog.scrollbox.layout.md_bg_color = self.theme_cls.surfaceContainerLowColor
dialog.scrollbox.layout.spacing = dp(5)
dialog.scrollbox.layout.padding = [0, dp(5), 0, 0]
if name not in self.options:
# convert from non-mutable to mutable
# We use list syntax even for sets, set behavior is enforced through GUI
if issubclass(option, OptionCounter):
self.options[name] = deepcopy(option.default)
else:
self.options[name] = sorted(option.default)
if issubclass(option, OptionCounter):
for value in sorted(self.options[name]):
dialog.add_set_item(value, self.options[name].get(value, None))
else:
for value in sorted(self.options[name]):
dialog.add_set_item(value)
dialog.save.bind(on_release=apply_changes)
dialog.open()
def create_option_set_list_counter(self, option: typing.Type[OptionList] | typing.Type[OptionSet] |
typing.Type[OptionCounter], name: str, world: typing.Type[World]):
main_button = MDButton(MDButtonText(text="Edit"), on_release=lambda x: self.create_popup(option, name, world))
return main_button
def create_option(self, option: typing.Type[Option], name: str, world: typing.Type[World]) -> Widget:
option_base = MDBoxLayout(orientation="vertical", size_hint_y=None, padding=[0, 0, dp(5), dp(5)])
tooltip = filter_tooltip(option.__doc__)
option_label = TooltipLabel(text=f"[ref=0|{tooltip}]{getattr(option, 'display_name', name)}")
label_box = MDBoxLayout(orientation="horizontal")
label_anchor = MDAnchorLayout(anchor_x="right", anchor_y="center")
label_anchor.add_widget(option_label)
label_box.add_widget(label_anchor)
option_base.add_widget(label_box)
if issubclass(option, NamedRange):
option_base.add_widget(self.create_named_range(option, name))
elif issubclass(option, Range):
option_base.add_widget(self.create_range(option, name))
elif issubclass(option, Toggle):
option_base.add_widget(self.create_toggle(option, name))
elif issubclass(option, TextChoice):
option_base.add_widget(self.create_text_choice(option, name))
elif issubclass(option, Choice):
option_base.add_widget(self.create_choice(option, name))
elif issubclass(option, FreeText):
option_base.add_widget(self.create_free_text(option, name))
elif any(issubclass(option, cls) for cls in (OptionSet, OptionList, OptionCounter)):
option_base.add_widget(self.create_option_set_list_counter(option, name, world))
else:
option_base.add_widget(MDLabel(text="This option isn't supported by the option creator.\n"
"Please edit your yaml manually to set this option."))
if option_can_be_randomized(option):
def randomize_option(instance: Widget, value: str):
value = value == "down"
if value:
self.options[name] = "random-" + str(self.options[name])
else:
self.options[name] = self.options[name].replace("random-", "")
if self.options[name].isnumeric():
self.options[name] = int(self.options[name])
elif self.options[name] in ("True", "False"):
self.options[name] = self.options[name] == "True"
base_object = instance.parent.parent
label_object = instance.parent
for child in base_object.children:
if child is not label_object:
child.disabled = value
default_random = option.default == "random"
random_toggle = ToggleButton(MDButtonText(text="Random?"), size_hint_x=None, width=dp(100),
state="down" if default_random else "normal")
random_toggle.bind(state=randomize_option)
label_box.add_widget(random_toggle)
if default_random:
randomize_option(random_toggle, "down")
return option_base
def create_options_panel(self, world_button: WorldButton):
self.option_layout.clear_widgets()
self.options.clear()
cls: typing.Type[World] = world_button.world_cls
self.current_game = cls.game
if not cls.web.options_page:
self.current_game = "None"
return
elif isinstance(cls.web.options_page, str):
self.current_game = "None"
if validate_url(cls.web.options_page):
webbrowser.open(cls.web.options_page)
MDSnackbar(MDSnackbarText(text="Launching in default browser..."), y=dp(24), pos_hint={"center_x": 0.5},
size_hint_x=0.5).open()
world_button.state = "normal"
else:
# attach onto archipelago.gg and see if we pass
new_url = "https://archipelago.gg/" + cls.web.options_page
if validate_url(new_url):
webbrowser.open(new_url)
MDSnackbar(MDSnackbarText(text="Launching in default browser..."), y=dp(24),
pos_hint={"center_x": 0.5},
size_hint_x=0.5).open()
else:
MDSnackbar(MDSnackbarText(text="Invalid options page, please report to world developer."), y=dp(24),
pos_hint={"center_x": 0.5},
size_hint_x=0.5).open()
world_button.state = "normal"
# else just fall through
else:
expansion_box = ScrollBox()
expansion_box.layout.orientation = "vertical"
expansion_box.layout.spacing = dp(3)
expansion_box.scroll_type = ["bars"]
expansion_box.do_scroll_x = False
group_names = ["Game Options", *(group.name for group in cls.web.option_groups)]
groups = {name: [] for name in group_names}
for name, option in cls.options_dataclass.type_hints.items():
group = next((group.name for group in cls.web.option_groups if option in group.options), "Game Options")
groups[group].append((name, option))
for group, options in groups.items():
options = [(name, option) for name, option in options
if name and option.visibility & Visibility.simple_ui]
if not options:
continue # Game Options can be empty if every other option is in another group
# Can also have an option group of options that should not render on simple ui
group_item = MDExpansionPanel(size_hint_y=None)
group_header = MDExpansionPanelHeader(MDListItem(MDListItemSupportingText(text=group),
TrailingPressedIconButton(icon="chevron-right",
on_release=lambda x,
item=group_item:
self.tap_expansion_chevron(
item, x)),
md_bg_color=self.theme_cls.surfaceContainerLowestColor,
theme_bg_color="Custom",
on_release=lambda x, item=group_item:
self.tap_expansion_chevron(item, x)))
group_content = MDExpansionPanelContent(orientation="vertical", theme_bg_color="Custom",
md_bg_color=self.theme_cls.surfaceContainerLowestColor,
padding=[dp(12), dp(100), dp(12), 0],
spacing=dp(3))
group_item.add_widget(group_header)
group_item.add_widget(group_content)
group_box = ScrollBox()
group_box.layout.orientation = "vertical"
group_box.layout.spacing = dp(3)
for name, option in options:
group_content.add_widget(self.create_option(option, name, cls))
expansion_box.layout.add_widget(group_item)
self.option_layout.add_widget(expansion_box)
self.game_label.text = f"Game: {self.current_game}"
@staticmethod
def tap_expansion_chevron(panel: MDExpansionPanel, chevron: TrailingPressedIconButton | MDListItem):
if isinstance(chevron, MDListItem):
chevron = next((child for child in chevron.ids.trailing_container.children
if isinstance(child, TrailingPressedIconButton)), None)
panel.open() if not panel.is_open else panel.close()
if chevron:
panel.set_chevron_down(
chevron
) if not panel.is_open else panel.set_chevron_up(chevron)
def build(self):
self.set_colors()
self.options = {}
self.container = Builder.load_file(Utils.local_path("data/optionscreator.kv"))
self.root = self.container
self.main_layout = self.container.ids.main
self.scrollbox = self.container.ids.scrollbox
def world_button_action(world_btn: WorldButton):
if self.current_game != world_btn.world_cls.game:
old_button = next((button for button in self.scrollbox.layout.children
if button.world_cls.game == self.current_game), None)
if old_button:
old_button.state = "normal"
else:
world_btn.state = "down"
self.create_options_panel(world_btn)
for world, cls in sorted(AutoWorldRegister.world_types.items(), key=lambda x: x[0]):
if cls.hidden:
continue
world_text = MDButtonText(text=world, size_hint_y=None, width=dp(150),
pos_hint={"x": 0.03, "center_y": 0.5})
world_text.text_size = (world_text.width, None)
world_text.bind(width=lambda *x, text=world_text: text.setter('text_size')(text, (text.width, None)),
texture_size=lambda *x, text=world_text: text.setter("height")(text,
world_text.texture_size[1]))
world_button = WorldButton(world_text, size_hint_x=None, width=dp(150), theme_width="Custom",
radius=(dp(5), dp(5), dp(5), dp(5)))
world_button.bind(on_release=world_button_action)
world_button.world_cls = cls
self.scrollbox.layout.add_widget(world_button)
self.main_panel = self.container.ids.player_layout
self.player_options = self.container.ids.player_options
self.game_label = self.container.ids.game
self.name_input = self.container.ids.player_name
self.option_layout = self.container.ids.options
def set_height(instance, value):
instance.height = value[1]
self.game_label.bind(texture_size=set_height)
# Uncomment to re-enable the Kivy console/live editor
# Ctrl-E to enable it, make sure numlock/capslock is disabled
# from kivy.modules.console import create_console
# from kivy.core.window import Window
# create_console(Window, self.container)
return self.container
def launch():
OptionsCreator().run()
if __name__ == "__main__":
Utils.init_logging("OptionsCreator")
launch()

View File

@@ -1,27 +1,25 @@
# [Archipelago](https://archipelago.gg) ![Discord Shield](https://discordapp.com/api/guilds/731205301247803413/widget.png?style=shield) | [Install](https://github.com/ArchipelagoMW/Archipelago/releases)
Archipelago provides a generic framework for developing multiworld capability for game randomizers. In all cases, presently, Archipelago is also the randomizer itself.
Archipelago provides a generic framework for developing multiworld capability for game randomizers. In all cases,
presently, Archipelago is also the randomizer itself.
Currently, the following games are supported:
* The Legend of Zelda: A Link to the Past
* Factorio
* Minecraft
* Subnautica
* Slay the Spire
* Risk of Rain 2
* The Legend of Zelda: Ocarina of Time
* Timespinner
* Super Metroid
* Secret of Evermore
* Final Fantasy
* Rogue Legacy
* VVVVVV
* Raft
* Super Mario 64
* Meritous
* Super Metroid/Link to the Past combo randomizer (SMZ3)
* ChecksFinder
* ArchipIDLE
* Hollow Knight
* The Witness
* Sonic Adventure 2: Battle
@@ -41,7 +39,6 @@ Currently, the following games are supported:
* The Messenger
* Kingdom Hearts 2
* The Legend of Zelda: Link's Awakening DX
* Clique
* Adventure
* DLC Quest
* Noita
@@ -61,13 +58,33 @@ Currently, the following games are supported:
* TUNIC
* Kirby's Dream Land 3
* Celeste 64
* Zork Grand Inquisitor
* Castlevania 64
* A Short Hike
* Yoshi's Island
* Mario & Luigi: Superstar Saga
* Bomb Rush Cyberfunk
* 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
* Civilization VI
* The Legend of Zelda: The Wind Waker
* Jak and Daxter: The Precursor Legacy
* Super Mario Land 2: 6 Golden Coins
* shapez
* Paint
* Celeste (Open World)
* Choo-Choo Charles
* APQuest
* Satisfactory
* EarthBound
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
@@ -75,36 +92,57 @@ windows binaries.
## History
Archipelago is built upon a strong legacy of brilliant hobbyists. We want to honor that legacy by showing it here. The repositories which Archipelago is built upon, inspired by, or otherwise owes its gratitude to are:
Archipelago is built upon a strong legacy of brilliant hobbyists. We want to honor that legacy by showing it here.
The repositories which Archipelago is built upon, inspired by, or otherwise owes its gratitude to are:
* [bonta0's MultiWorld](https://github.com/Bonta0/ALttPEntranceRandomizer/tree/multiworld_31)
* [AmazingAmpharos' Entrance Randomizer](https://github.com/AmazingAmpharos/ALttPEntranceRandomizer)
* [VT Web Randomizer](https://github.com/sporchia/alttp_vt_randomizer)
* [Dessyreqt's alttprandomizer](https://github.com/Dessyreqt/alttprandomizer)
* [Zarby89's](https://github.com/Ijwu/Enemizer/commits?author=Zarby89) and [sosuke3's](https://github.com/Ijwu/Enemizer/commits?author=sosuke3) contributions to Enemizer, which make the vast majority of Enemizer contributions.
* [Zarby89's](https://github.com/Ijwu/Enemizer/commits?author=Zarby89)
and [sosuke3's](https://github.com/Ijwu/Enemizer/commits?author=sosuke3) contributions to Enemizer, which make up the
vast majority of Enemizer contributions.
We recognize that there is a strong community of incredibly smart people that have come before us and helped pave the path. Just because one person's name may be in a repository title does not mean that only one person made that project happen. We can't hope to perfectly cover every single contribution that lead up to Archipelago but we hope to honor them fairly.
We recognize that there is a strong community of incredibly smart people that have come before us and helped pave the
path. Just because one person's name may be in a repository title does not mean that only one person made that project
happen. We can't hope to perfectly cover every single contribution that lead up to Archipelago, but we hope to honor
them fairly.
### Path to the Archipelago
Archipelago was directly forked from bonta0's `multiworld_31` branch of ALttPEntranceRandomizer (this project has a long legacy of its own, please check it out linked above) on January 12, 2020. The repository was then named to _MultiWorld-Utilities_ to better encompass its intended function. As Archipelago matured, then known as "Berserker's MultiWorld" by some, we found it necessary to transform our repository into a root level repository (as opposed to a 'forked repo') and change the name (which came later) to better reflect our project.
Archipelago was directly forked from bonta0's `multiworld_31` branch of ALttPEntranceRandomizer (this project has a
long legacy of its own, please check it out linked above) on January 12, 2020. The repository was then named to
_MultiWorld-Utilities_ to better encompass its intended function. As Archipelago matured, then known as
"Berserker's MultiWorld" by some, we found it necessary to transform our repository into a root level repository
(as opposed to a 'forked repo') and change the name (which came later) to better reflect our project.
## Running Archipelago
For most people, all you need to do is head over to the [releases](https://github.com/ArchipelagoMW/Archipelago/releases) page then download and run the appropriate installer, or AppImage for Linux-based systems.
If you are a developer or are running on a platform with no compiled releases available, please see our doc on [running Archipelago from source](docs/running%20from%20source.md).
For most people, all you need to do is head over to
the [releases page](https://github.com/ArchipelagoMW/Archipelago/releases), then download and run the appropriate
installer, or AppImage for Linux-based systems.
If you are a developer or are running on a platform with no compiled releases available, please see our doc on
[running Archipelago from source](docs/running%20from%20source.md).
## Related Repositories
This project makes use of multiple other projects. We wouldn't be here without these other repositories and the contributions of their developers, past and present.
This project makes use of multiple other projects. We wouldn't be here without these other repositories and the
contributions of their developers, past and present.
* [z3randomizer](https://github.com/ArchipelagoMW/z3randomizer)
* [Enemizer](https://github.com/Ijwu/Enemizer)
* [Ocarina of Time Randomizer](https://github.com/TestRunnerSRL/OoT-Randomizer)
## Contributing
For contribution guidelines, please see our [Contributing doc.](/docs/contributing.md)
To contribute to Archipelago, including the WebHost, core program, or by adding a new game, see our
[Contributing guidelines](/docs/contributing.md).
## FAQ
For Frequently asked questions, please see the website's [FAQ Page.](https://archipelago.gg/faq/en/)
For Frequently asked questions, please see the website's [FAQ Page](https://archipelago.gg/faq/en/).
## Code of Conduct
Please refer to our [code of conduct.](/docs/code_of_conduct.md)
Please refer to our [code of conduct](/docs/code_of_conduct.md).

View File

@@ -18,6 +18,7 @@ from json import loads, dumps
from CommonClient import CommonContext, server_loop, ClientCommandProcessor, gui_enabled, get_base_parser
import Utils
import settings
from Utils import async_start
from MultiServer import mark_raw
if typing.TYPE_CHECKING:
@@ -243,6 +244,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
@@ -282,7 +286,7 @@ class SNESState(enum.IntEnum):
def launch_sni() -> None:
sni_path = Utils.get_settings()["sni_options"]["sni_path"]
sni_path = settings.get_settings().sni_options.sni_path
if not os.path.isdir(sni_path):
sni_path = Utils.local_path(sni_path)
@@ -633,7 +637,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,12 +659,17 @@ 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:
auto_start = typing.cast(typing.Union[bool, str],
Utils.get_settings()["sni_options"].get("snes_rom_start", True))
auto_start = settings.get_settings().sni_options.snes_rom_start
if auto_start is True:
import webbrowser
webbrowser.open(romfile)
@@ -720,6 +735,6 @@ async def main() -> None:
if __name__ == '__main__':
colorama.init()
colorama.just_fix_windows_console()
asyncio.run(main())
colorama.deinit()

View File

@@ -1,11 +0,0 @@
from __future__ import annotations
import ModuleUpdate
ModuleUpdate.update()
from worlds.sc2.Client import launch
import Utils
if __name__ == "__main__":
Utils.init_logging("Starcraft2Client", exception_logger="Client")
launch()

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[l.item])):
toDraw += str(ctx.item_names[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)
@@ -500,7 +500,7 @@ def main():
import colorama
colorama.init()
colorama.just_fix_windows_console()
asyncio.run(_main())
colorama.deinit()

591
Utils.py
View File

@@ -1,6 +1,7 @@
from __future__ import annotations
import asyncio
import concurrent.futures
import json
import typing
import builtins
@@ -18,9 +19,10 @@ 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
from pathspec import PathSpec, GitIgnoreSpec
try:
from yaml import CLoader as UnsafeLoader, CSafeLoader as SafeLoader, CDumper as Dumper
@@ -31,10 +33,11 @@ if typing.TYPE_CHECKING:
import tkinter
import pathlib
from BaseClasses import Region
import multiprocessing
def tuplize_version(version: str) -> Version:
return Version(*(int(piece, 10) for piece in version.split(".")))
return Version(*(int(piece) for piece in version.split(".")))
class Version(typing.NamedTuple):
@@ -46,7 +49,7 @@ class Version(typing.NamedTuple):
return ".".join(str(item) for item in self)
__version__ = "0.4.6"
__version__ = "0.6.7"
version_tuple = tuplize_version(__version__)
is_linux = sys.platform.startswith("linux")
@@ -101,8 +104,7 @@ def cache_self1(function: typing.Callable[[S, T], RetType]) -> typing.Callable[[
@functools.wraps(function)
def wrap(self: S, arg: T) -> RetType:
cache: Optional[Dict[T, RetType]] = typing.cast(Optional[Dict[T, RetType]],
getattr(self, cache_name, None))
cache: Optional[Dict[T, RetType]] = getattr(self, cache_name, None)
if cache is None:
res = function(self, arg)
setattr(self, cache_name, {arg: res})
@@ -114,6 +116,8 @@ def cache_self1(function: typing.Callable[[S, T], RetType]) -> typing.Callable[[
cache[arg] = res
return res
wrap.__defaults__ = function.__defaults__
return wrap
@@ -137,8 +141,11 @@ def local_path(*path: str) -> str:
local_path.cached_path = os.path.dirname(os.path.abspath(sys.argv[0]))
else:
import __main__
if hasattr(__main__, "__file__") and os.path.isfile(__main__.__file__):
if globals().get("__file__") and os.path.isfile(__file__):
# we are running in a normal Python environment
local_path.cached_path = os.path.dirname(os.path.abspath(__file__))
elif hasattr(__main__, "__file__") and os.path.isfile(__main__.__file__):
# we are running in a normal Python environment, but AP was imported weirdly
local_path.cached_path = os.path.dirname(os.path.abspath(__main__.__file__))
else:
# pray
@@ -152,7 +159,18 @@ 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')
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)
elif sys.platform == 'darwin':
import platformdirs
home_path.cached_path = platformdirs.user_data_dir("Archipelago", False)
os.makedirs(home_path.cached_path, 0o700, exist_ok=True)
else:
# not implemented
@@ -165,7 +183,7 @@ def user_path(*path: str) -> str:
"""Returns either local_path or home_path based on write permissions."""
if hasattr(user_path, "cached_path"):
pass
elif os.access(local_path(), os.W_OK):
elif os.access(local_path(), os.W_OK) and not (is_macos and is_frozen()):
user_path.cached_path = local_path()
else:
user_path.cached_path = home_path()
@@ -209,11 +227,17 @@ def output_path(*path: str) -> str:
def open_file(filename: typing.Union[str, "pathlib.Path"]) -> None:
if is_windows:
os.startfile(filename)
os.startfile(filename) # type: ignore
else:
from shutil import which
open_command = which("open") if is_macos else (which("xdg-open") or which("gnome-open") or which("kde-open"))
subprocess.call([open_command, filename])
assert open_command, "Didn't find program for open_file! Please report this together with system details."
env = os.environ
if "LD_LIBRARY_PATH" in env:
env = env.copy()
del env["LD_LIBRARY_PATH"] # exe is a system binary, so reset LD_LIBRARY_PATH
subprocess.call([open_command, filename], env=env)
# from https://gist.github.com/pypt/94d747fe5180851196eb#gistcomment-4015118 with some changes
@@ -291,30 +315,28 @@ def get_public_ipv6() -> str:
return ip
OptionsType = Settings # TODO: remove when removing get_options
def get_options() -> Settings:
# TODO: switch to Utils.deprecate after 0.4.4
warnings.warn("Utils.get_options() is deprecated. Use the settings API instead.", DeprecationWarning)
deprecate("Utils.get_options() is deprecated. Use the settings API instead.")
return get_settings()
def persistent_store(category: str, key: typing.Any, value: typing.Any):
def persistent_store(category: str, key: str, value: typing.Any, force_store: bool = False):
storage = persistent_load()
if not force_store and category in storage and key in storage[category] and storage[category][key] == value:
return # no changes necessary
category_dict = storage.setdefault(category, {})
category_dict[key] = value
path = user_path("_persistent_storage.yaml")
storage: dict = persistent_load()
category = storage.setdefault(category, {})
category[key] = value
with open(path, "wt") as f:
f.write(dump(storage, Dumper=Dumper))
def persistent_load() -> typing.Dict[str, dict]:
storage = getattr(persistent_load, "storage", None)
def persistent_load() -> Dict[str, Dict[str, Any]]:
storage: Union[Dict[str, Dict[str, Any]], None] = getattr(persistent_load, "storage", None)
if storage:
return storage
path = user_path("_persistent_storage.yaml")
storage: dict = {}
storage = {}
if os.path.exists(path):
try:
with open(path, "r") as f:
@@ -323,7 +345,7 @@ def persistent_load() -> typing.Dict[str, dict]:
logging.debug(f"Could not read store: {e}")
if storage is None:
storage = {}
persistent_load.storage = storage
setattr(persistent_load, "storage", storage)
return storage
@@ -365,6 +387,15 @@ def store_data_package_for_checksum(game: str, data: typing.Dict[str, Any]) -> N
except Exception as e:
logging.debug(f"Could not store data package: {e}")
def read_apignore(filename: str | pathlib.Path) -> PathSpec | None:
try:
with open(filename) as ignore_file:
return GitIgnoreSpec.from_lines(ignore_file)
except FileNotFoundError:
return None
def get_default_adjuster_settings(game_name: str) -> Namespace:
import LttPAdjuster
adjuster_settings = Namespace()
@@ -383,18 +414,33 @@ def get_adjuster_settings(game_name: str) -> Namespace:
default_settings = get_default_adjuster_settings(game_name)
# Fill in any arguments from the argparser that we haven't seen before
return Namespace(**vars(adjuster_settings), **{k:v for k,v in vars(default_settings).items() if k not in vars(adjuster_settings)})
return Namespace(**vars(adjuster_settings), **{
k: v for k, v in vars(default_settings).items() if k not in vars(adjuster_settings)
})
@cache_argsless
def get_unique_identifier():
uuid = persistent_load().get("client", {}).get("uuid", None)
common_path = cache_path("common.json")
try:
with open(common_path) as f:
common_file = json.load(f)
uuid = common_file.get("uuid", None)
except FileNotFoundError:
common_file = {}
uuid = None
if uuid:
return uuid
import uuid
uuid = uuid.getnode()
persistent_store("client", "uuid", uuid)
from uuid import uuid4
uuid = str(uuid4())
common_file["uuid"] = uuid
cache_folder = os.path.dirname(common_path)
os.makedirs(cache_folder, exist_ok=True)
with open(common_path, "w") as f:
json.dump(common_file, f, separators=(",", ":"))
return uuid
@@ -407,20 +453,25 @@ safe_builtins = frozenset((
class RestrictedUnpickler(pickle.Unpickler):
generic_properties_module: Optional[object]
def __init__(self, *args, **kwargs):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super(RestrictedUnpickler, self).__init__(*args, **kwargs)
self.options_module = importlib.import_module("Options")
self.net_utils_module = importlib.import_module("NetUtils")
self.generic_properties_module = None
def find_class(self, module, name):
def find_class(self, module: str, name: str) -> type:
if module == "builtins" and name in safe_builtins:
return getattr(builtins, name)
# used by OptionCounter
# necessary because the actual Options class instances are pickled when transfered to WebHost generation pool
if module == "collections" and name == "Counter":
return collections.Counter
# 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)
@@ -431,17 +482,30 @@ 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,
self.options_module.PlandoItem, self.options_module.PlandoText)):
return obj
# Forbid everything else.
raise pickle.UnpicklingError(f"global '{module}.{name}' is forbidden")
def restricted_loads(s):
def restricted_loads(s: bytes) -> Any:
"""Helper function analogous to pickle.loads()."""
return RestrictedUnpickler(io.BytesIO(s)).load()
def restricted_dumps(obj: Any) -> bytes:
"""Helper function analogous to pickle.dumps()."""
s = pickle.dumps(obj)
# Assert that the string can be successfully loaded by restricted_loads
try:
restricted_loads(s)
except pickle.UnpicklingError as e:
raise pickle.PicklingError(e) from e
return s
class ByValue:
"""
Mixin for enums to pickle value instead of name (restores pre-3.11 behavior). Use as left-most parent.
@@ -455,6 +519,15 @@ class KeyedDefaultDict(collections.defaultdict):
"""defaultdict variant that uses the missing key as argument to default_factory"""
default_factory: typing.Callable[[typing.Any], typing.Any]
def __init__(self,
default_factory: typing.Callable[[Any], Any] = None,
seq: typing.Union[typing.Mapping, typing.Iterable, None] = None,
**kwargs):
if seq is not None:
super().__init__(default_factory, seq, **kwargs)
else:
super().__init__(default_factory, **kwargs)
def __missing__(self, key):
self[key] = value = self.default_factory(key)
return value
@@ -471,9 +544,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")
@@ -493,19 +566,25 @@ def init_logging(name: str, loglevel: typing.Union[str, int] = logging.INFO, wri
file_handler.setFormatter(logging.Formatter(log_format))
class Filter(logging.Filter):
def __init__(self, filter_name, condition):
def __init__(self, filter_name: str, condition: typing.Callable[[logging.LogRecord], bool]) -> None:
super().__init__(filter_name)
self.condition = condition
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)
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
# Relay unhandled exceptions to logger.
if not getattr(sys.excepthook, "_wrapped", False): # skip if already modified
@@ -516,7 +595,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
@@ -539,12 +619,13 @@ 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 ''}"
)
def stream_input(stream, queue):
def stream_input(stream: typing.TextIO, queue: "asyncio.Queue[str]"):
def queuer():
while 1:
try:
@@ -554,6 +635,8 @@ def stream_input(stream, queue):
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)
@@ -572,7 +655,7 @@ class VersionException(Exception):
pass
def chaining_prefix(index: int, labels: typing.Tuple[str]) -> str:
def chaining_prefix(index: int, labels: typing.Sequence[str]) -> str:
text = ""
max_label = len(labels) - 1
while index > max_label:
@@ -595,47 +678,117 @@ def format_SI_prefix(value, power=1000, power_labels=("", "k", "M", "G", "T", "P
return f"{value.quantize(decimal.Decimal('1.00'))} {chaining_prefix(n, power_labels)}"
def get_fuzzy_results(input_word: str, wordlist: typing.Sequence[str], limit: typing.Optional[int] = None) \
def get_fuzzy_results(input_word: str, word_list: typing.Collection[str], limit: typing.Optional[int] = None) \
-> typing.List[typing.Tuple[str, int]]:
import jellyfish
def get_fuzzy_ratio(word1: str, word2: str) -> float:
if word1 == word2:
return 1.01
return (1 - jellyfish.damerau_levenshtein_distance(word1.lower(), word2.lower())
/ max(len(word1), len(word2)))
limit: int = limit if limit else len(wordlist)
limit = limit if limit else len(word_list)
return list(
map(
lambda container: (container[0], int(container[1]*100)), # convert up to limit to int %
sorted(
map(lambda candidate:
(candidate, get_fuzzy_ratio(input_word, candidate)),
wordlist),
map(lambda candidate: (candidate, get_fuzzy_ratio(input_word, candidate)), word_list),
key=lambda element: element[1],
reverse=True)[0:limit]
reverse=True
)[0:limit]
)
)
def open_filename(title: str, filetypes: typing.Sequence[typing.Tuple[str, typing.Sequence[str]]], suggest: str = "") \
def get_intended_text(input_text: str, possible_answers) -> typing.Tuple[str, bool, str]:
picks = get_fuzzy_results(input_text, possible_answers, limit=2)
if len(picks) > 1:
dif = picks[0][1] - picks[1][1]
if picks[0][1] == 101:
return picks[0][0], True, "Perfect Match"
elif picks[0][1] == 100:
return picks[0][0], True, "Case Insensitive Perfect Match"
elif picks[0][1] < 75:
return picks[0][0], False, f"Didn't find something that closely matches '{input_text}', " \
f"did you mean '{picks[0][0]}'? ({picks[0][1]}% sure)"
elif dif > 5:
return picks[0][0], True, "Close Match"
else:
return picks[0][0], False, f"Too many close matches for '{input_text}', " \
f"did you mean '{picks[0][0]}'? ({picks[0][1]}% sure)"
else:
if picks[0][1] > 90:
return picks[0][0], True, "Only Option Match"
else:
return picks[0][0], False, f"Didn't find something that closely matches '{input_text}', " \
f"did you mean '{picks[0][0]}'? ({picks[0][1]}% sure)"
def get_input_text_from_response(text: str, command: str) -> typing.Optional[str]:
"""
Parses the response text from `get_intended_text` to find the suggested input and autocomplete the command in
arguments with it.
:param text: The response text from `get_intended_text`.
:param command: The command to which the input text should be added. Must contain the prefix used by the command
(`!` or `/`).
:return: The command with the suggested input text appended, or None if no suggestion was found.
"""
if "did you mean " in text:
for question in ("Didn't find something that closely matches",
"Too many close matches"):
if text.startswith(question):
name = get_text_between(text, "did you mean '",
"'? (")
return f"{command} {name}"
elif text.startswith("Missing: "):
return text.replace("Missing: ", "!hint_location ")
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 _mp_save_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(save_filename(*args))
def _run_for_stdout(*args: str):
env = os.environ
if "LD_LIBRARY_PATH" in env:
env = env.copy()
del env["LD_LIBRARY_PATH"] # exe is a system binary, so reset LD_LIBRARY_PATH
return subprocess.run(args, capture_output=True, text=True, env=env).stdout.split("\n", 1)[0] or None
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}.")
def run(*args: str):
return subprocess.run(args, capture_output=True, text=True).stdout.split("\n", 1)[0] or None
if is_linux:
# prefer native dialog
from shutil import which
kdialog = which("kdialog")
if kdialog:
k_filters = '|'.join((f'{text} (*{" *".join(ext)})' for (text, ext) in filetypes))
return run(kdialog, f"--title={title}", "--getopenfilename", suggest or ".", k_filters)
return _run_for_stdout(kdialog, f"--title={title}", "--getopenfilename", suggest or ".", k_filters)
zenity = which("zenity")
if zenity:
z_filters = (f'--file-filter={text} ({", ".join(ext)}) | *{" *".join(ext)}' for (text, ext) in filetypes)
selection = (f"--filename={suggest}",) if suggest else ()
return run(zenity, f"--title={title}", "--file-selection", *z_filters, *selection)
return _run_for_stdout(zenity, f"--title={title}", "--file-selection", *z_filters, *selection)
# fall back to tk
try:
@@ -646,31 +799,44 @@ def open_filename(title: str, filetypes: typing.Sequence[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:
return None # GUI not available. None is the same as a user clicking "cancel"
root.withdraw()
return tkinter.filedialog.askopenfilename(title=title, filetypes=((t[0], ' '.join(t[1])) for t in filetypes),
initialfile=suggest or None)
try:
return tkinter.filedialog.askopenfilename(
title=title,
filetypes=((t[0], ' '.join(t[1])) for t in filetypes),
initialfile=suggest or None,
)
finally:
root.destroy()
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
def save_filename(title: str, filetypes: typing.Iterable[typing.Tuple[str, typing.Iterable[str]]], suggest: str = "") \
-> typing.Optional[str]:
logging.info(f"Opening file save dialog for {title}.")
if is_linux:
# prefer native dialog
from shutil import which
kdialog = which("kdialog")
if kdialog:
return run(kdialog, f"--title={title}", "--getexistingdirectory",
os.path.abspath(suggest) if suggest else ".")
k_filters = '|'.join((f'{text} (*{" *".join(ext)})' for (text, ext) in filetypes))
return _run_for_stdout(kdialog, f"--title={title}", "--getsavefilename", suggest or ".", k_filters)
zenity = which("zenity")
if zenity:
z_filters = ("--directory",)
selection = (f"--filename={os.path.abspath(suggest)}/",) if suggest else ()
return run(zenity, f"--title={title}", "--file-selection", *z_filters, *selection)
z_filters = (f'--file-filter={text} ({", ".join(ext)}) | *{" *".join(ext)}' for (text, ext) in filetypes)
selection = (f"--filename={suggest}",) if suggest else ()
return _run_for_stdout(zenity, f"--title={title}", "--file-selection", "--save", *z_filters, *selection)
# fall back to tk
try:
@@ -678,9 +844,67 @@ 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 save_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_save_filename, args=(res, title, filetypes, suggest)).start()
return res.get()
try:
root = tkinter.Tk()
except tkinter.TclError:
return None # GUI not available. None is the same as a user clicking "cancel"
root.withdraw()
try:
return tkinter.filedialog.asksaveasfilename(
title=title,
filetypes=((t[0], ' '.join(t[1])) for t in filetypes),
initialfile=suggest or None,
)
finally:
root.destroy()
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]:
if is_linux:
# prefer native dialog
from shutil import which
kdialog = which("kdialog")
if kdialog:
return _run_for_stdout(kdialog, f"--title={title}", "--getexistingdirectory",
os.path.abspath(suggest) if suggest else ".")
zenity = which("zenity")
if zenity:
z_filters = ("--directory",)
selection = (f"--filename={os.path.abspath(suggest)}/",) if suggest else ()
return _run_for_stdout(zenity, f"--title={title}", "--file-selection", *z_filters, *selection)
# fall back to tk
try:
import tkinter
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_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:
@@ -690,14 +914,12 @@ def open_directory(title: str, suggest: str = "") -> typing.Optional[str]:
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 not gui_enabled:
if error:
logging.error(f"{title}: {text}")
else:
logging.info(f"{title}: {text}")
return
if is_kivy_running():
from kvui import MessageBox
@@ -709,10 +931,10 @@ def messagebox(title: str, text: str, error: bool = False) -> None:
from shutil import which
kdialog = which("kdialog")
if kdialog:
return run(kdialog, f"--title={title}", "--error" if error else "--msgbox", text)
return _run_for_stdout(kdialog, f"--title={title}", "--error" if error else "--msgbox", text)
zenity = which("zenity")
if zenity:
return run(zenity, f"--title={title}", f"--text={text}", "--error" if error else "--info")
return _run_for_stdout(zenity, f"--title={title}", f"--text={text}", "--error" if error else "--info")
elif is_windows:
import ctypes
@@ -734,7 +956,10 @@ def messagebox(title: str, text: str, error: bool = False) -> None:
root.update()
def title_sorted(data: typing.Sequence, key=None, ignore: typing.Set = frozenset(("a", "the"))):
gui_enabled = not sys.stdout or "--nogui" not in sys.argv
"""Checks if the user wanted no GUI mode and has a terminal to use it with."""
def title_sorted(data: typing.Iterable, key=None, ignore: typing.AbstractSet[str] = frozenset(("a", "the"))):
"""Sorts a sequence of text ignoring typical articles like "a" or "the" in the beginning."""
def sorter(element: Union[str, Dict[str, Any]]) -> str:
if (not isinstance(element, str)):
@@ -764,7 +989,7 @@ def async_start(co: Coroutine[None, None, typing.Any], name: Optional[str] = Non
Use this to start a task when you don't keep a reference to it or immediately await it,
to prevent early garbage collection. "fire-and-forget"
"""
# https://docs.python.org/3.10/library/asyncio-task.html#asyncio.create_task
# https://docs.python.org/3.11/library/asyncio-task.html#asyncio.create_task
# Python docs:
# ```
# Important: Save a reference to the result of [asyncio.create_task],
@@ -777,41 +1002,39 @@ 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):
log_message: str
should_error: bool
def __init__(self, message, error: bool = False) -> None:
def __init__(self, message: str, error: bool = False) -> None:
self.log_message = message
self.should_error = error
super().__init__()
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)
def _extend_freeze_support() -> None:
"""Extend multiprocessing.freeze_support() to also work on Non-Windows for spawn."""
# upstream issue: https://github.com/python/cpython/issues/76327
"""Extend multiprocessing.freeze_support() to also work on Non-Windows and without setting spawn method first."""
# original upstream issue: https://github.com/python/cpython/issues/76327
# code based on https://github.com/pyinstaller/pyinstaller/blob/develop/PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py#L26
import multiprocessing
import multiprocessing.spawn
def _freeze_support() -> None:
"""Minimal freeze_support. Only apply this if frozen."""
from subprocess import _args_from_interpreter_flags
from subprocess import _args_from_interpreter_flags # noqa
# Prevent `spawn` from trying to read `__main__` in from the main script
multiprocessing.process.ORIGINAL_DIR = None
@@ -819,8 +1042,7 @@ def _extend_freeze_support() -> None:
# Handle the first process that MP will create
if (
len(sys.argv) >= 2 and sys.argv[-2] == '-c' and sys.argv[-1].startswith((
'from multiprocessing.semaphore_tracker import main', # Py<3.8
'from multiprocessing.resource_tracker import main', # Py>=3.8
'from multiprocessing.resource_tracker import main',
'from multiprocessing.forkserver import main'
)) and set(sys.argv[1:-2]) == set(_args_from_interpreter_flags())
):
@@ -839,20 +1061,35 @@ def _extend_freeze_support() -> None:
multiprocessing.spawn.spawn_main(**kwargs)
sys.exit()
if not is_windows and is_frozen():
multiprocessing.freeze_support = multiprocessing.spawn.freeze_support = _freeze_support
def _noop() -> None:
pass
multiprocessing.freeze_support = multiprocessing.spawn.freeze_support = _freeze_support if is_frozen() else _noop
def freeze_support() -> None:
"""This behaves like multiprocessing.freeze_support but also works on Non-Windows."""
"""This now only calls multiprocessing.freeze_support since we are patching freeze_support on module load."""
import multiprocessing
_extend_freeze_support()
deprecate("Use multiprocessing.freeze_support() instead")
multiprocessing.freeze_support()
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:
_extend_freeze_support()
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,
regions_to_highlight: set[Region] | None = None,
entrance_highlighting: dict[int, int] | None = None,
detail_other_regions: bool = False,
auto_assign_colors: bool = False) -> 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.)
@@ -868,16 +1105,29 @@ 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.
:param entrance_highlighting: a mapping from your world's entrance randomization groups to RGB values, used to color
your entrances
:param detail_other_regions: (default False) If enabled, will fully visualize regions that aren't reachable
from root_region.
:param auto_assign_colors: (default False) If enabled, will automatically assign random colors to entrances of the
same randomization group. Uses entrance_highlighting first, and only picks random colors for entrance groups
not found in the passed-in map
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
@@ -888,6 +1138,34 @@ def visualize_regions(root_region: Region, file_name: str, *,
regions: typing.Deque[Region] = deque((root_region,))
multiworld: MultiWorld = root_region.multiworld
colors_used: set[int] = set()
if entrance_highlighting:
for color in entrance_highlighting.values():
# filter the colors to their most-significant bits to avoid too similar colors
colors_used.add(color & 0xF0F0F0)
else:
# assign an empty dict to not crash later
# the parameter is optional for ease of use when you don't care about colors
entrance_highlighting = {}
def select_color(group: int) -> int:
# specifically spacing color indexes by three different prime numbers (3, 5, 7) for the RGB components to avoid
# obvious cyclical color patterns
COLOR_INDEX_SPACING: int = 0x357
new_color_index: int = (group * COLOR_INDEX_SPACING) % 0x1000
new_color = ((new_color_index & 0xF00) << 12) + \
((new_color_index & 0xF0) << 8) + \
((new_color_index & 0xF) << 4)
while new_color in colors_used:
# while this is technically unbounded, expected collisions are low. There are 4095 possible colors
# and worlds are unlikely to get to anywhere close to that many entrance groups
# intentionally not using multiworld.random to not affect output when debugging with this tool
new_color_index += COLOR_INDEX_SPACING
new_color = ((new_color_index & 0xF00) << 12) + \
((new_color_index & 0xF0) << 8) + \
((new_color_index & 0xF) << 4)
return new_color
def fmt(obj: Union[Entrance, Item, Location, Region]) -> str:
name = obj.name
if isinstance(obj, Item):
@@ -907,18 +1185,28 @@ def visualize_regions(root_region: Region, file_name: str, *,
def visualize_exits(region: Region) -> None:
for exit_ in region.exits:
color_code: str = ""
if exit_.randomization_group in entrance_highlighting:
color_code = f" #{entrance_highlighting[exit_.randomization_group]:0>6X}"
if exit_.connected_region:
if show_entrance_names:
uml.append(f"\"{fmt(region)}\" --> \"{fmt(exit_.connected_region)}\" : \"{fmt(exit_)}\"")
uml.append(f"\"{fmt(region)}\" --> \"{fmt(exit_.connected_region)}\" : \"{fmt(exit_)}\"{color_code}")
else:
try:
uml.remove(f"\"{fmt(exit_.connected_region)}\" --> \"{fmt(region)}\"")
uml.append(f"\"{fmt(exit_.connected_region)}\" <--> \"{fmt(region)}\"")
uml.remove(f"\"{fmt(exit_.connected_region)}\" --> \"{fmt(region)}\"{color_code}")
uml.append(f"\"{fmt(exit_.connected_region)}\" <--> \"{fmt(region)}\"{color_code}")
except ValueError:
uml.append(f"\"{fmt(region)}\" --> \"{fmt(exit_.connected_region)}\"")
uml.append(f"\"{fmt(region)}\" --> \"{fmt(exit_.connected_region)}\"{color_code}")
else:
uml.append(f"circle \"unconnected exit:\\n{fmt(exit_)}\"")
uml.append(f"\"{fmt(region)}\" --> \"unconnected exit:\\n{fmt(exit_)}\"")
uml.append(f"circle \"unconnected exit:\\n{fmt(exit_)}\" {color_code}")
uml.append(f"\"{fmt(region)}\" --> \"unconnected exit:\\n{fmt(exit_)}\"{color_code}")
for entrance in region.entrances:
color_code: str = ""
if entrance.randomization_group in entrance_highlighting:
color_code = f" #{entrance_highlighting[entrance.randomization_group]:0>6X}"
if not entrance.parent_region:
uml.append(f"circle \"unconnected entrance:\\n{fmt(entrance)}\"{color_code}")
uml.append(f"\"unconnected entrance:\\n{fmt(entrance)}\" --> \"{fmt(region)}\"{color_code}")
def visualize_locations(region: Region) -> None:
any_lock = any(location.locked for location in region.locations)
@@ -930,7 +1218,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)
@@ -939,9 +1227,27 @@ def visualize_regions(root_region: Region, file_name: str, *,
if other_regions := [region for region in multiworld.get_regions(root_region.player) if region not in seen]:
uml.append("package \"other regions\" <<Cloud>> {")
for region in other_regions:
uml.append(f"class \"{fmt(region)}\"")
if detail_other_regions:
visualize_region(region)
else:
uml.append(f"class \"{fmt(region)}\"")
uml.append("}")
if auto_assign_colors:
all_entrances: list[Entrance] = []
for region in multiworld.get_regions(root_region.player):
all_entrances.extend(region.entrances)
all_entrances.extend(region.exits)
all_groups: list[int] = sorted(set([entrance.randomization_group for entrance in all_entrances]))
for group in all_groups:
if group not in entrance_highlighting:
if len(colors_used) >= 0x1000:
# on the off chance someone makes 4096 different entrance groups, don't cycle forever
break
new_color: int = select_color(group)
entrance_highlighting[group] = new_color
colors_used.add(new_color)
uml.append("@startuml")
uml.append("hide circle")
uml.append("hide empty members")
@@ -952,7 +1258,7 @@ def visualize_regions(root_region: Region, file_name: str, *,
seen.add(current_region)
visualize_region(current_region)
regions.extend(exit_.connected_region for exit_ in current_region.exits if exit_.connected_region)
if show_other_regions:
if show_other_regions or detail_other_regions:
visualize_other_regions()
uml.append("@enduml")
@@ -979,3 +1285,72 @@ def is_iterable_except_str(obj: object) -> TypeGuard[typing.Iterable[typing.Any]
if isinstance(obj, str):
return False
return isinstance(obj, typing.Iterable)
class DaemonThreadPoolExecutor(concurrent.futures.ThreadPoolExecutor):
"""
ThreadPoolExecutor that uses daemonic threads that do not keep the program alive.
NOTE: use this with caution because killed threads will not properly clean up.
"""
def _adjust_thread_count(self):
# see upstream ThreadPoolExecutor for details
import threading
import weakref
from concurrent.futures.thread import _worker
if self._idle_semaphore.acquire(timeout=0):
return
def weakref_cb(_, q=self._work_queue):
q.put(None)
num_threads = len(self._threads)
if num_threads < self._max_workers:
thread_name = f"{self._thread_name_prefix or self}_{num_threads}"
t = threading.Thread(
name=thread_name,
target=_worker,
args=(
weakref.ref(self, weakref_cb),
self._work_queue,
self._initializer,
self._initargs,
),
daemon=True,
)
t.start()
self._threads.add(t)
# NOTE: don't add to _threads_queues so we don't block on shutdown
def get_full_typename(t: type) -> str:
"""Returns the full qualified name of a type, including its module (if not builtins)."""
module = t.__module__
if module and module != "builtins":
return f"{module}.{t.__qualname__}"
return t.__qualname__
def get_all_causes(ex: Exception) -> str:
"""Return a string describing the recursive causes of this exception.
:param ex: The exception to be described.
:return A multiline string starting with the initial exception on the first line and each resulting exception
on subsequent lines with progressive indentation.
For example:
```
Exception: Invalid value 'bad'.
Which caused: Options.OptionError: Error generating option
Which caused: ValueError: File bad.yaml is invalid.
```
"""
cause = ex
causes = [f"{get_full_typename(type(ex))}: {ex}"]
while cause := cause.__cause__:
causes.append(f"{get_full_typename(type(cause))}: {cause}")
top = causes[-1]
others = "".join(f"\n{' ' * (i + 1)}Which caused: {c}" for i, c in enumerate(reversed(causes[:-1])))
return f"{top}{others}"

View File

@@ -1,3 +1,4 @@
import argparse
import os
import multiprocessing
import logging
@@ -11,15 +12,20 @@ ModuleUpdate.update()
# in case app gets imported by something like gunicorn
import Utils
import settings
from Utils import get_file_safe_name
Utils.local_path.cached_path = os.path.dirname(__file__) or "." # py3.8 is not abs. remove "." when dropping 3.8
if typing.TYPE_CHECKING:
from flask import Flask
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
if not os.path.exists(configpath):
# fall back to config.yaml in user_path if config does not exist in cwd to match settings.py
configpath = os.path.abspath(Utils.user_path('config.yaml'))
def get_app():
def get_app() -> "Flask":
from WebHostLib import register, cache, app as raw_app
from WebHostLib.models import db
@@ -28,6 +34,15 @@ def get_app():
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()
@@ -40,24 +55,24 @@ def get_app():
return app
def create_ordered_tutorials_file() -> typing.List[typing.Dict[str, typing.Any]]:
import json
def copy_tutorials_files_to_static() -> None:
import shutil
import zipfile
from werkzeug.utils import secure_filename
zfile: zipfile.ZipInfo
from worlds.AutoWorld import AutoWorldRegister
worlds = {}
data = []
for game, world in AutoWorldRegister.world_types.items():
if hasattr(world.web, 'tutorials') and (not world.hidden or game == 'Archipelago'):
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, secure_filename(game))
os.makedirs(target_path, exist_ok=True)
if world.zip_path:
@@ -70,45 +85,14 @@ def create_ordered_tutorials_file() -> typing.List[typing.Dict[str, typing.Any]]
for zfile in zf.infolist():
if not zfile.is_dir() and "/docs/" in zfile.filename:
zfile.filename = os.path.basename(zfile.filename)
zf.extract(zfile, target_path)
with open(os.path.join(target_path, secure_filename(zfile.filename)), "wb") as f:
f.write(zf.read(zfile))
else:
source_path = Utils.local_path(os.path.dirname(world.__file__), "docs")
files = os.listdir(source_path)
for file in files:
shutil.copyfile(Utils.local_path(source_path, file), Utils.local_path(target_path, file))
# build a json tutorial dict per game
game_data = {'gameTitle': game, 'tutorials': []}
for tutorial in world.web.tutorials:
# build dict for the json file
current_tutorial = {
'name': tutorial.tutorial_name,
'description': tutorial.description,
'files': [{
'language': tutorial.language,
'filename': game + '/' + tutorial.file_name,
'link': f'{game}/{tutorial.link}',
'authors': tutorial.authors
}]
}
# check if the name of the current guide exists already
for guide in game_data['tutorials']:
if guide and tutorial.tutorial_name == guide['name']:
guide['files'].append(current_tutorial['files'][0])
break
else:
game_data['tutorials'].append(current_tutorial)
data.append(game_data)
with open(Utils.local_path("WebHostLib", "static", "generated", "tutorials.json"), 'w', encoding='utf-8-sig') as json_target:
generic_data = {}
for games in data:
if 'Archipelago' in games['gameTitle']:
generic_data = data.pop(data.index(games))
sorted_data = [generic_data] + Utils.title_sorted(data, key=lambda entry: entry["gameTitle"])
json.dump(sorted_data, json_target, indent=2, ensure_ascii=False)
return sorted_data
shutil.copyfile(Utils.local_path(source_path, file),
Utils.local_path(target_path, secure_filename(file)))
if __name__ == "__main__":
@@ -116,18 +100,25 @@ if __name__ == "__main__":
multiprocessing.set_start_method('spawn')
logging.basicConfig(format='[%(asctime)s] %(message)s', level=logging.INFO)
from WebHostLib.lttpsprites import update_sprites_lttp
from WebHostLib.autolauncher import autohost, autogen
from WebHostLib.autolauncher import autohost, autogen, stop
from WebHostLib.options import create as create_options_files
try:
from WebHostLib.lttpsprites import update_sprites_lttp
update_sprites_lttp()
except Exception as e:
logging.exception(e)
logging.warning("Could not update LttP sprites.")
app = get_app()
from worlds import AutoWorldRegister
# Update to only valid WebHost worlds
invalid_worlds = {name for name, world in AutoWorldRegister.world_types.items()
if not hasattr(world.web, "tutorials")}
if invalid_worlds:
logging.error(f"Following worlds not loaded as they are invalid for WebHost: {invalid_worlds}")
AutoWorldRegister.world_types = {k: v for k, v in AutoWorldRegister.world_types.items() if k not in invalid_worlds}
create_options_files()
create_ordered_tutorials_file()
copy_tutorials_files_to_static()
if app.config["SELFLAUNCH"]:
autohost(app.config)
if app.config["SELFGEN"]:
@@ -138,3 +129,11 @@ if __name__ == "__main__":
else:
from waitress import serve
serve(app, port=app.config["PORT"], threads=app.config["WAITRESS_THREADS"])
else:
from time import sleep
try:
while True:
sleep(1) # wait for process to be killed
except (SystemExit, KeyboardInterrupt):
pass
stop() # stop worker threads

View File

@@ -1,46 +1,20 @@
# WebHost
## Asset License
The image files used in the page design were specifically designed for archipelago.gg and are **not** covered by the top
level LICENSE.
See individual LICENSE files in `./static/static/**`.
You are only allowed to use them for personal use, testing and development.
If the site is reachable over the internet, have a robots.txt in place (see `ASSET_RIGHTS` in `config.yaml`)
and do not promote it publicly. Alternatively replace or remove the assets.
## Contribution Guidelines
**Thank you for your interest in contributing to the Archipelago website!**
Much of the content on the website is generated automatically, but there are some things
that need a personal touch. For those things, we rely on contributions from both the core
team and the community. The current primary maintainer of the website is Farrak Kilhn.
He may be found on Discord as `Farrak Kilhn#0418`, or on GitHub as `LegendaryLinux`.
### Small Changes
Little changes like adding a button or a couple new select elements are perfectly fine.
Tweaks to style specific to a PR's content are also probably not a problem. For example, if
you build a new page which needs two side by side tables, and you need to write a CSS file
specific to your page, that is perfectly reasonable.
Pages should preferably be rendered on the server side with Jinja. Features should work with noscript if feasible.
Design changes have to fit the overall design.
### Content Additions
Once you develop a new feature or add new content the website, make a pull request. It will
be reviewed by the community and there will probably be some discussion around it. Depending
on the size of the feature, and if new styles are required, there may be an additional step
before the PR is accepted wherein Farrak works with the designer to implement styles.
Introduction of JS dependencies should first be discussed on Discord or in a draft PR.
### Restrictions on Style Changes
A professional designer is paid to develop the styles and assets for the Archipelago website.
In an effort to maintain a consistent look and feel, pull requests which *exclusively*
change site styles are rejected. Please note this applies to code which changes the overall
look and feel of the site, not to small tweaks to CSS for your custom page. The intention
behind these restrictions is to maintain a curated feel for the design of the site. If
any PR affects the overall feel of the site but includes additive changes, there will
likely be a conversation about how to implement those changes without compromising the
curated site style. It is therefore worth noting there are a couple files which, if
changed in your pull request, will cause it to draw additional scrutiny.
These closely guarded files are:
- `globalStyles.css`
- `islandFooter.css`
- `landing.css`
- `markdown.css`
- `tooltip.css`
### Site Themes
There are several themes available for game pages. It is possible to request a new theme in
the `#art-and-design` channel on Discord. Because themes are created by the designer, they
are not free, and take some time to create. Farrak works closely with the designer to implement
these themes, and pays for the assets out of pocket. Therefore, only a couple themes per year
are added. If a proposed theme seems like a cool idea and the community likes it, there is a
good chance it will become a reality.
See also [docs/style.md](/docs/style.md) for the style guide.

View File

@@ -1,6 +1,7 @@
import base64
import os
import socket
import typing
import uuid
from flask import Flask
@@ -9,7 +10,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,7 +21,19 @@ 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
# overwrites of flask default config
app.config["DEBUG"] = False
app.config["PORT"] = 80
app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER
app.config["MAX_CONTENT_LENGTH"] = 64 * 1024 * 1024 # 64 megabyte limit
# if you want to deploy, make sure you have a non-guessable secret key
app.config["SECRET_KEY"] = bytes(socket.gethostname(), encoding="utf-8")
app.config["SESSION_PERMANENT"] = True
app.config["MAX_FORM_MEMORY_SIZE"] = 2 * 1024 * 1024 # 2 MB, needed for large option pages such as SC2
# custom config
app.config["SELFHOST"] = True # application process is in charge of running the websites
app.config["GENERATORS"] = 8 # maximum concurrent world gens
app.config["HOSTERS"] = 8 # maximum concurrent room hosters
@@ -28,17 +41,12 @@ app.config["SELFLAUNCH"] = True # application process is in charge of launching
app.config["SELFLAUNCHCERT"] = None # can point to a SSL Certificate to encrypt Room websocket connections
app.config["SELFLAUNCHKEY"] = None # can point to a SSL Certificate Key to encrypt Room websocket connections
app.config["SELFGEN"] = True # application process is in charge of scheduling Generations.
app.config["DEBUG"] = False
app.config["PORT"] = 80
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 64 * 1024 * 1024 # 64 megabyte limit
# if you want to deploy, make sure you have a non-guessable secret key
app.config["SECRET_KEY"] = bytes(socket.gethostname(), encoding="utf-8")
# at what amount of worlds should scheduling be used, instead of rolling in the web-thread
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
app.config['SESSION_PERMANENT'] = True
# memory limit for generator processes in bytes
app.config["GENERATOR_MEMORY_LIMIT"] = 4294967296
# waitress uses one thread for I/O, these are for processing of views that then get sent
# archipelago.gg uses gunicorn + nginx; ignoring this option
@@ -58,32 +66,44 @@ cache = Cache()
Compress(app)
def to_python(value: str) -> uuid.UUID:
return uuid.UUID(bytes=base64.urlsafe_b64decode(value + '=='))
def to_url(value: uuid.UUID) -> str:
return base64.urlsafe_b64encode(value.bytes).rstrip(b'=').decode('ascii')
class B64UUIDConverter(BaseConverter):
def to_python(self, value):
return uuid.UUID(bytes=base64.urlsafe_b64decode(value + '=='))
def to_python(self, value: str) -> uuid.UUID:
return to_python(value)
def to_url(self, value):
return base64.urlsafe_b64encode(value.bytes).rstrip(b'=').decode('ascii')
def to_url(self, value: typing.Any) -> str:
assert isinstance(value, uuid.UUID)
return to_url(value)
# short UUID
app.url_map.converters["suuid"] = B64UUIDConverter
app.jinja_env.filters['suuid'] = lambda value: base64.urlsafe_b64encode(value.bytes).rstrip(b'=').decode('ascii')
app.jinja_env.filters["suuid"] = to_url
app.jinja_env.filters["title_sorted"] = title_sorted
def register():
def register() -> None:
"""Import submodules, triggering their registering on flask routing.
Note: initializes worlds subsystem."""
import importlib
from werkzeug.utils import find_modules
# has automatic patch integration
import worlds.AutoWorld
import worlds.Files
app.jinja_env.filters['supports_apdeltapatch'] = lambda game_name: \
game_name in worlds.Files.AutoPatchRegister.patch_types
app.jinja_env.filters['is_applayercontainer'] = worlds.Files.is_ap_player_container
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
for module in find_modules("WebHostLib", include_packages=True):
importlib.import_module(module)
from . import api
app.register_blueprint(api.api_endpoints)

View File

@@ -1,78 +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 .. import cache
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,
}
@api_endpoints.route('/datapackage')
@cache.cached()
def get_datapackage():
from worlds import network_data_package
return network_data_package
@api_endpoints.route('/datapackage_version')
@cache.cached()
def get_datapackage_versions():
from worlds import AutoWorldRegister
version_package = {game: world.data_version for game, world in AutoWorldRegister.world_types.items()}
return version_package
@api_endpoints.route('/datapackage_checksum')
@cache.cached()
def get_datapackage_checksums():
from worlds import network_data_package
version_package = {
game: game_data["checksum"] for game, game_data in network_data_package["games"].items()
}
return version_package
from . import generate, user # trigger registration
# trigger endpoint registration
from . import datapackage, generate, room, tracker, user

View File

@@ -0,0 +1,32 @@
from flask import abort
from Utils import restricted_loads
from WebHostLib import cache
from WebHostLib.models import GameDataPackage
from . import api_endpoints
@api_endpoints.route('/datapackage')
@cache.cached()
def get_datapackage():
from worlds import network_data_package
return network_data_package
@api_endpoints.route('/datapackage/<string:checksum>')
@cache.memoize(timeout=3600)
def get_datapackage_by_checksum(checksum: str):
package = GameDataPackage.get(checksum=checksum)
if package:
return restricted_loads(package.data)
return abort(404)
@api_endpoints.route('/datapackage_checksum')
@cache.cached()
def get_datapackage_checksums():
from worlds import network_data_package
version_package = {
game: game_data["checksum"] for game, game_data in network_data_package["games"].items()
}
return version_package

View File

@@ -1,11 +1,11 @@
import json
import pickle
from uuid import UUID
from flask import request, session, url_for
from markupsafe import Markup
from pony.orm import commit
from Utils import restricted_dumps
from WebHostLib import app
from WebHostLib.check import get_yaml_data, roll_options
from WebHostLib.generate import get_meta
@@ -56,7 +56,7 @@ def generate_api():
"detail": results}, 400
else:
gen = Generation(
options=pickle.dumps({name: vars(options) for name, options in gen_options.items()}),
options=restricted_dumps({name: vars(options) for name, options in gen_options.items()}),
# convert to json compatible
meta=json.dumps(meta), state=STATE_QUEUED,
owner=session["_id"])

43
WebHostLib/api/room.py Normal file
View File

@@ -0,0 +1,43 @@
from typing import Any, Dict
from uuid import UUID
from flask import abort, url_for
from WebHostLib import to_url
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": to_url(room.tracker),
"players": get_players(room.seed),
"last_port": room.last_port,
"last_activity": room.last_activity,
"timeout": room.timeout,
"downloads": downloads,
}

258
WebHostLib/api/tracker.py Normal file
View File

@@ -0,0 +1,258 @@
from datetime import datetime, timezone
from typing import Any, TypedDict
from uuid import UUID
from flask import abort
from NetUtils import ClientStatus, Hint, NetworkItem, SlotType
from WebHostLib import cache
from WebHostLib.api import api_endpoints
from WebHostLib.models import Room
from WebHostLib.tracker import TrackerData
class PlayerAlias(TypedDict):
team: int
player: int
alias: str | None
class PlayerItemsReceived(TypedDict):
team: int
player: int
items: list[NetworkItem]
class PlayerChecksDone(TypedDict):
team: int
player: int
locations: list[int]
class TeamTotalChecks(TypedDict):
team: int
checks_done: int
class PlayerHints(TypedDict):
team: int
player: int
hints: list[Hint]
class PlayerTimer(TypedDict):
team: int
player: int
time: datetime | None
class PlayerStatus(TypedDict):
team: int
player: int
status: ClientStatus
class PlayerLocationsTotal(TypedDict):
team: int
player: int
total_locations: int
class PlayerGame(TypedDict):
team: int
player: int
game: str
@api_endpoints.route("/tracker/<suuid:tracker>")
@cache.memoize(timeout=60)
def tracker_data(tracker: UUID) -> dict[str, Any]:
"""
Outputs json data to <root_path>/api/tracker/<id of current session tracker>.
:param tracker: UUID of current session tracker.
:return: Tracking data for all players in the room. Typing and docstrings describe the format of each value.
"""
room: Room | None = Room.get(tracker=tracker)
if not room:
abort(404)
tracker_data = TrackerData(room)
all_players: dict[int, list[int]] = tracker_data.get_all_players()
player_aliases: list[PlayerAlias] = []
"""Slot aliases of all players."""
for team, players in all_players.items():
for player in players:
player_aliases.append(
{"team": team, "player": player, "alias": tracker_data.get_player_alias(team, player)})
player_items_received: list[PlayerItemsReceived] = []
"""Items received by each player."""
for team, players in all_players.items():
for player in players:
player_items_received.append(
{"team": team, "player": player, "items": tracker_data.get_player_received_items(team, player)})
player_checks_done: list[PlayerChecksDone] = []
"""ID of all locations checked by each player."""
for team, players in all_players.items():
for player in players:
player_checks_done.append(
{"team": team, "player": player,
"locations": sorted(tracker_data.get_player_checked_locations(team, player))})
total_checks_done: list[TeamTotalChecks] = [
{"team": team, "checks_done": checks_done}
for team, checks_done in tracker_data.get_team_locations_checked_count().items()
]
"""Total number of locations checked for the entire multiworld per team."""
hints: list[PlayerHints] = []
"""Hints that all players have used or received."""
for team, players in tracker_data.get_all_slots().items():
for player in players:
player_hints = sorted(tracker_data.get_player_hints(team, player))
hints.append({"team": team, "player": player, "hints": player_hints})
slot_info = tracker_data.get_slot_info(player)
# this assumes groups are always after players
if slot_info.type != SlotType.group:
continue
for member in slot_info.group_members:
hints[member - 1]["hints"] += player_hints
activity_timers: list[PlayerTimer] = []
"""Time of last activity per player. Returned as RFC 1123 format and null if no connection has been made."""
for team, players in all_players.items():
for player in players:
activity_timers.append({"team": team, "player": player, "time": None})
for (team, player), timestamp in tracker_data._multisave.get("client_activity_timers", []):
for entry in activity_timers:
if entry["team"] == team and entry["player"] == player:
entry["time"] = datetime.fromtimestamp(timestamp, timezone.utc)
break
connection_timers: list[PlayerTimer] = []
"""Time of last connection per player. Returned as RFC 1123 format and null if no connection has been made."""
for team, players in all_players.items():
for player in players:
connection_timers.append({"team": team, "player": player, "time": None})
for (team, player), timestamp in tracker_data._multisave.get("client_connection_timers", []):
# find the matching entry
for entry in connection_timers:
if entry["team"] == team and entry["player"] == player:
entry["time"] = datetime.fromtimestamp(timestamp, timezone.utc)
break
player_status: list[PlayerStatus] = []
"""The current client status for each player."""
for team, players in all_players.items():
for player in players:
player_status.append(
{"team": team, "player": player, "status": tracker_data.get_player_client_status(team, player)})
return {
"aliases": player_aliases,
"player_items_received": player_items_received,
"player_checks_done": player_checks_done,
"total_checks_done": total_checks_done,
"hints": hints,
"activity_timers": activity_timers,
"connection_timers": connection_timers,
"player_status": player_status,
}
class PlayerGroups(TypedDict):
slot: int
name: str
members: list[int]
class PlayerSlotData(TypedDict):
player: int
slot_data: dict[str, Any]
@api_endpoints.route("/static_tracker/<suuid:tracker>")
@cache.memoize(timeout=300)
def static_tracker_data(tracker: UUID) -> dict[str, Any]:
"""
Outputs json data to <root_path>/api/static_tracker/<id of current session tracker>.
:param tracker: UUID of current session tracker.
:return: Static tracking data for all players in the room. Typing and docstrings describe the format of each value.
"""
room: Room | None = Room.get(tracker=tracker)
if not room:
abort(404)
tracker_data = TrackerData(room)
all_players: dict[int, list[int]] = tracker_data.get_all_players()
groups: list[PlayerGroups] = []
"""The Slot ID of groups and the IDs of the group's members."""
for team, players in tracker_data.get_all_slots().items():
for player in players:
slot_info = tracker_data.get_slot_info(player)
if slot_info.type != SlotType.group or not slot_info.group_members:
continue
groups.append(
{
"slot": player,
"name": slot_info.name,
"members": list(slot_info.group_members),
})
break
player_locations_total: list[PlayerLocationsTotal] = []
for team, players in all_players.items():
for player in players:
player_locations_total.append(
{"team": team, "player": player, "total_locations": len(tracker_data.get_player_locations(player))})
player_game: list[PlayerGame] = []
"""The played game per player slot."""
for team, players in all_players.items():
for player in players:
player_game.append({"team": team, "player": player, "game": tracker_data.get_player_game(player)})
return {
"groups": groups,
"datapackage": tracker_data._multidata["datapackage"],
"player_locations_total": player_locations_total,
"player_game": player_game,
}
# It should be exceedingly rare that slot data is needed, so it's separated out.
@api_endpoints.route("/slot_data_tracker/<suuid:tracker>")
@cache.memoize(timeout=300)
def tracker_slot_data(tracker: UUID) -> list[PlayerSlotData]:
"""
Outputs json data to <root_path>/api/slot_data_tracker/<id of current session tracker>.
:param tracker: UUID of current session tracker.
:return: Slot data for all players in the room. Typing completely arbitrary per game.
"""
room: Room | None = Room.get(tracker=tracker)
if not room:
abort(404)
tracker_data = TrackerData(room)
all_players: dict[int, list[int]] = tracker_data.get_all_players()
slot_data: list[PlayerSlotData] = []
"""Slot data for each player."""
for team, players in all_players.items():
for player in players:
slot_data.append({"player": player, "slot_data": tracker_data.get_slot_data(player)})
break
return slot_data

View File

@@ -1,6 +1,7 @@
from flask import session, jsonify
from pony.orm import select
from WebHostLib import to_url
from WebHostLib.models import Room, Seed
from . import api_endpoints, get_players
@@ -10,13 +11,13 @@ def get_rooms():
response = []
for room in select(room for room in Room if room.owner == session["_id"]):
response.append({
"room_id": room.id,
"seed_id": room.seed.id,
"room_id": to_url(room.id),
"seed_id": to_url(room.seed.id),
"creation_time": room.creation_time,
"last_activity": room.last_activity,
"last_port": room.last_port,
"timeout": room.timeout,
"tracker": room.tracker,
"tracker": to_url(room.tracker),
})
return jsonify(response)
@@ -26,8 +27,8 @@ def get_seeds():
response = []
for seed in select(seed for seed in Seed if seed.owner == session["_id"]):
response.append({
"seed_id": seed.id,
"seed_id": to_url(seed.id),
"creation_time": seed.creation_time,
"players": get_players(seed.slots),
"players": get_players(seed),
})
return jsonify(response)
return jsonify(response)

View File

@@ -3,16 +3,27 @@ from __future__ import annotations
import json
import logging
import multiprocessing
import time
import typing
from uuid import UUID
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
from pony.orm import db_session, select, commit, PrimaryKey
from Utils import restricted_loads
from .locker import Locker, AlreadyRunningException
_stop_event = Event()
def stop() -> None:
"""Stops previously launched threads"""
global _stop_event
stop_event = _stop_event
_stop_event = Event() # new event for new threads
stop_event.set()
def handle_generation_success(seed_id):
logging.info(f"Generation finished for seed {seed_id}")
@@ -25,16 +36,39 @@ def handle_generation_failure(result: BaseException):
logging.exception(e)
def launch_generator(pool: multiprocessing.pool.Pool, generation: Generation):
def _mp_gen_game(
gen_options: dict,
meta: dict[str, Any] | None = None,
owner=None,
sid=None,
timeout: int|None = None,
) -> PrimaryKey | None:
from setproctitle import setproctitle
setproctitle(f"Generator ({sid})")
try:
return gen_game(gen_options, meta=meta, owner=owner, sid=sid, timeout=timeout)
finally:
setproctitle(f"Generator (idle)")
def launch_generator(pool: multiprocessing.pool.Pool, generation: Generation, timeout: int|None) -> None:
try:
meta = json.loads(generation.meta)
options = restricted_loads(generation.options)
logging.info(f"Generating {generation.id} for {len(options)} players")
pool.apply_async(gen_game, (options,),
{"meta": meta,
"sid": generation.id,
"owner": generation.owner},
handle_generation_success, handle_generation_failure)
pool.apply_async(
_mp_gen_game,
(options,),
{
"meta": meta,
"sid": generation.id,
"owner": generation.owner,
"timeout": timeout,
},
handle_generation_success,
handle_generation_failure,
)
except Exception as e:
generation.state = STATE_ERROR
commit()
@@ -43,7 +77,25 @@ 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:
from setproctitle import setproctitle
setproctitle("Generator (idle)")
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()
@@ -63,6 +115,7 @@ def cleanup():
def autohost(config: dict):
def keep_running():
stop_event = _stop_event
try:
with Locker("autohost"):
cleanup()
@@ -72,31 +125,31 @@ def autohost(config: dict):
hosters.append(hoster)
hoster.start()
while 1:
time.sleep(0.1)
while not stop_event.wait(0.1):
with db_session:
rooms = select(
room for room in Room if
room.last_activity >= datetime.utcnow() - timedelta(days=3))
for room in rooms:
# we have to filter twice, as the per-room timeout can't currently be PonyORM transpiled.
if room.last_activity >= datetime.utcnow() - timedelta(seconds=room.timeout):
if room.last_activity >= datetime.utcnow() - timedelta(seconds=room.timeout + 5):
hosters[room.id.int % len(hosters)].start_room(room.id)
except AlreadyRunningException:
logging.info("Autohost reports as already running, not starting another.")
import threading
threading.Thread(target=keep_running, name="AP_Autohost").start()
Thread(target=keep_running, name="AP_Autohost").start()
def autogen(config: dict):
def keep_running():
stop_event = _stop_event
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:
job_time = config["JOB_TIME"]
with db_session:
to_start = select(generation for generation in Generation if generation.state == STATE_STARTED)
@@ -107,28 +160,23 @@ def autogen(config: dict):
if sid:
generation.delete()
else:
launch_generator(generator_pool, generation)
launch_generator(generator_pool, generation, timeout=job_time)
commit()
select(generation for generation in Generation if generation.state == STATE_ERROR).delete()
while 1:
time.sleep(0.1)
while not stop_event.wait(0.1):
with db_session:
# for update locks the database row(s) during transaction, preventing writes from elsewhere
to_start = select(
generation for generation in Generation
if generation.state == STATE_QUEUED).for_update()
for generation in to_start:
launch_generator(generator_pool, generation)
launch_generator(generator_pool, generation, timeout=job_time)
except AlreadyRunningException:
logging.info("Autogen reports as already running, not starting another.")
import threading
threading.Thread(target=keep_running, name="AP_Autogen").start()
multiworlds: typing.Dict[type(Room.id), MultiworldInstance] = {}
Thread(target=keep_running, name="AP_Autogen").start()
class MultiworldInstance():

View File

@@ -1,7 +1,7 @@
import os
import zipfile
import base64
from typing import Union, Dict, Set, Tuple
from collections.abc import Set
from flask import request, flash, redirect, url_for, render_template
from markupsafe import Markup
@@ -43,7 +43,7 @@ def mysterycheck():
return redirect(url_for("check"), 301)
def get_yaml_data(files) -> Union[Dict[str, str], str, Markup]:
def get_yaml_data(files) -> dict[str, str] | str | Markup:
options = {}
for uploaded_file in files:
if banned_file(uploaded_file.filename):
@@ -84,12 +84,12 @@ def get_yaml_data(files) -> Union[Dict[str, str], str, Markup]:
return options
def roll_options(options: Dict[str, Union[dict, str]],
def roll_options(options: dict[str, dict | str],
plando_options: Set[str] = frozenset({"bosses", "items", "connections", "texts"})) -> \
Tuple[Dict[str, Union[str, bool]], Dict[str, dict]]:
tuple[dict[str, str | bool], dict[str, dict]]:
plando_options = PlandoOptions.from_set(set(plando_options))
results = {}
rolled_results = {}
results: dict[str, str | bool] = {}
rolled_results: dict[str, dict] = {}
for filename, text in options.items():
try:
if type(text) is dict:
@@ -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

@@ -19,7 +19,10 @@ from pony.orm import commit, db_session, select
import Utils
from MultiServer import Context, server, auto_shutdown, ServerCommandProcessor, ClientMessageProcessor, load_server_cert
from MultiServer import (
Context, server, auto_shutdown, ServerCommandProcessor, ClientMessageProcessor, load_server_cert,
server_per_message_deflate_factory,
)
from Utils import restricted_loads, cache_argsless
from .locker import Locker
from .models import Command, GameDataPackage, Room, db
@@ -72,23 +75,38 @@ 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
setattr(self, key, value)
self.non_hintable_names = collections.defaultdict(frozenset, self.non_hintable_names)
def listen_to_db_commands(self):
async def listen_to_db_commands(self):
cmdprocessor = DBCommandProcessor(self)
while not self.exit_event.is_set():
with db_session:
commands = select(command for command in Command if command.room.id == self.room_id)
if commands:
for command in commands:
self.main_loop.call_soon_threadsafe(cmdprocessor, command.commandtext)
command.delete()
commit()
time.sleep(5)
await self.main_loop.run_in_executor(None, self._process_db_commands, cmdprocessor)
try:
await asyncio.wait_for(self.exit_event.wait(), 5)
except asyncio.TimeoutError:
pass
def _process_db_commands(self, cmdprocessor):
with db_session:
commands = select(command for command in Command if command.room.id == self.room_id)
if commands:
for command in commands:
self.main_loop.call_soon_threadsafe(cmdprocessor, command.commandtext)
command.delete()
commit()
@db_session
def load(self, room_id: int):
@@ -101,33 +119,56 @@ class WebHostContext(Context):
multidata = self.decompress(room.seed.multidata)
game_data_packages = {}
static_gamespackage = self.gamespackage # this is shared across all rooms
static_item_name_groups = self.item_name_groups
static_location_name_groups = self.location_name_groups
self.gamespackage = {"Archipelago": static_gamespackage.get("Archipelago", {})} # this may be modified by _load
self.item_name_groups = {"Archipelago": static_item_name_groups.get("Archipelago", {})}
self.location_name_groups = {"Archipelago": static_location_name_groups.get("Archipelago", {})}
missing_checksum = False
for game in list(multidata.get("datapackage", {})):
game_data = multidata["datapackage"][game]
if "checksum" in game_data:
if self.gamespackage.get(game, {}).get("checksum") == game_data["checksum"]:
# non-custom. remove from multidata
if static_gamespackage.get(game, {}).get("checksum") == game_data["checksum"]:
# non-custom. remove from multidata and use static data
# games package could be dropped from static data once all rooms embed data package
del multidata["datapackage"][game]
else:
row = GameDataPackage.get(checksum=game_data["checksum"])
if row: # None if rolled on >= 0.3.9 but uploaded to <= 0.3.8. multidata should be complete
game_data_packages[game] = Utils.restricted_loads(row.data)
game_data_packages[game] = restricted_loads(row.data)
continue
else:
self.logger.warning(f"Did not find game_data_package for {game}: {game_data['checksum']}")
else:
missing_checksum = True # Game rolled on old AP and will load data package from multidata
self.gamespackage[game] = static_gamespackage.get(game, {})
self.item_name_groups[game] = static_item_name_groups.get(game, {})
self.location_name_groups[game] = static_location_name_groups.get(game, {})
if not game_data_packages and not missing_checksum:
# all static -> use the static dicts directly
self.gamespackage = static_gamespackage
self.item_name_groups = static_item_name_groups
self.location_name_groups = static_location_name_groups
return self._load(multidata, game_data_packages, True)
@db_session
def init_save(self, enabled: bool = True):
self.saving = enabled
if self.saving:
savegame_data = Room.get(id=self.room_id).multisave
if savegame_data:
self.set_save(restricted_loads(Room.get(id=self.room_id).multisave))
self._start_async_saving()
threading.Thread(target=self.listen_to_db_commands, daemon=True).start()
with db_session:
savegame_data = Room.get(id=self.room_id).multisave
if savegame_data:
self.set_save(restricted_loads(savegame_data))
self._start_async_saving(atexit_save=False)
asyncio.create_task(self.listen_to_db_commands())
@db_session
def _save(self, exit_save: bool = False) -> bool:
room = Room.get(id=self.room_id)
# Does not use Utils.restricted_dumps because we'd rather make a save than not make one
room.multisave = pickle.dumps(self.get_save())
# saving only occurs on activity, so we can "abuse" this information to mark this as last_activity
if not exit_save: # we don't want to count a shutdown as activity, which would restart the server again
@@ -148,17 +189,28 @@ def get_random_port():
def get_static_server_data() -> dict:
import worlds
data = {
"non_hintable_names": {},
"gamespackage": worlds.network_data_package["games"],
"item_name_groups": {world_name: world.item_name_groups for world_name, world in
worlds.AutoWorldRegister.world_types.items()},
"location_name_groups": {world_name: world.location_name_groups for world_name, world in
worlds.AutoWorldRegister.world_types.items()},
"non_hintable_names": {
world_name: world.hint_blacklist
for world_name, world in worlds.AutoWorldRegister.world_types.items()
},
"gamespackage": {
world_name: {
key: value
for key, value in game_package.items()
if key not in ("item_name_groups", "location_name_groups")
}
for world_name, game_package in worlds.network_data_package["games"].items()
},
"item_name_groups": {
world_name: world.item_name_groups
for world_name, world in worlds.AutoWorldRegister.world_types.items()
},
"location_name_groups": {
world_name: world.location_name_groups
for world_name, world in worlds.AutoWorldRegister.world_types.items()
},
}
for world_name, world in worlds.AutoWorldRegister.world_types.items():
data["non_hintable_names"][world_name] = world.hint_blacklist
return data
@@ -182,9 +234,23 @@ def set_up_logging(room_id) -> logging.Logger:
return logger
def tear_down_logging(room_id):
"""Close logging handling for a room."""
logger_name = f"RoomLogger {room_id}"
if logger_name in logging.Logger.manager.loggerDict:
logger = logging.getLogger(logger_name)
for handler in logger.handlers[:]:
logger.removeHandler(handler)
handler.close()
del logging.Logger.manager.loggerDict[logger_name]
def run_server_process(name: str, ponyconfig: dict, static_server_data: dict,
cert_file: typing.Optional[str], cert_key_file: typing.Optional[str],
host: str, rooms_to_run: multiprocessing.Queue, rooms_shutting_down: multiprocessing.Queue):
from setproctitle import setproctitle
setproctitle(name)
Utils.init_logging(name)
try:
import resource
@@ -205,75 +271,140 @@ def run_server_process(name: str, ponyconfig: dict, static_server_data: dict,
raise Exception("Worlds system should not be loaded in the custom server.")
import gc
ssl_context = load_server_cert(cert_file, cert_key_file) if cert_file else None
del cert_file, cert_key_file, ponyconfig
if not cert_file:
def get_ssl_context():
return None
else:
load_date = None
ssl_context = load_server_cert(cert_file, cert_key_file)
def get_ssl_context():
nonlocal load_date, ssl_context
today = datetime.date.today()
if load_date != today:
ssl_context = load_server_cert(cert_file, cert_key_file)
load_date = today
return ssl_context
del ponyconfig
gc.collect() # free intermediate objects used during setup
loop = asyncio.get_event_loop()
async def start_room(room_id):
try:
logger = set_up_logging(room_id)
ctx = WebHostContext(static_server_data, logger)
ctx.load(room_id)
ctx.init_save()
with Locker(f"RoomLocker {room_id}"):
try:
ctx.server = websockets.serve(functools.partial(server, ctx=ctx), ctx.host, ctx.port, ssl=ssl_context)
logger = set_up_logging(room_id)
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=get_ssl_context(),
extensions=[server_per_message_deflate_factory],
)
await ctx.server
except OSError: # likely port in use
ctx.server = websockets.serve(
functools.partial(server, ctx=ctx), ctx.host, 0, ssl=get_ssl_context())
await ctx.server
except OSError: # likely port in use
ctx.server = websockets.serve(functools.partial(server, ctx=ctx), ctx.host, 0, ssl=ssl_context)
await ctx.server
port = 0
for wssocket in ctx.server.ws_server.sockets:
socketname = wssocket.getsockname()
if wssocket.family == socket.AF_INET6:
# Prefer IPv4, as most users seem to not have working ipv6 support
if not port:
await ctx.server
port = 0
for wssocket in ctx.server.ws_server.sockets:
socketname = wssocket.getsockname()
if wssocket.family == socket.AF_INET6:
# Prefer IPv4, as most users seem to not have working ipv6 support
if not port:
port = socketname[1]
elif wssocket.family == socket.AF_INET:
port = socketname[1]
elif wssocket.family == socket.AF_INET:
port = socketname[1]
if port:
ctx.logger.info(f'Hosting game at {host}:{port}')
if port:
ctx.logger.info(f'Hosting game at {host}:{port}')
with db_session:
room = Room.get(id=ctx.room_id)
room.last_port = port
del room
else:
ctx.logger.exception("Could not determine port. Likely hosting failure.")
with db_session:
room = Room.get(id=ctx.room_id)
room.last_port = port
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
except (KeyboardInterrupt, SystemExit):
if ctx.saving:
ctx._save(True)
setattr(asyncio.current_task(), "save", None)
except Exception as e:
with db_session:
room = Room.get(id=room_id)
room.last_port = -1
del room
logger.exception(e)
raise
else:
ctx.logger.exception("Could not determine port. Likely hosting failure.")
with db_session:
ctx.auto_shutdown = Room.get(id=room_id).timeout
ctx.shutdown_task = asyncio.create_task(auto_shutdown(ctx, []))
await ctx.shutdown_task
if ctx.saving:
ctx._save(True)
setattr(asyncio.current_task(), "save", None)
finally:
try:
ctx.save_dirty = False # make sure the saving thread does not write to DB after final wakeup
ctx.exit_event.set() # make sure the saving thread stops at some point
# NOTE: async saving should probably be an async task and could be merged with shutdown_task
# ensure auto launch is on the same page in regard to room activity.
with db_session:
room: Room = Room.get(id=ctx.room_id)
room.last_activity = datetime.datetime.utcnow() - datetime.timedelta(seconds=room.timeout + 60)
if ctx.server and hasattr(ctx.server, "ws_server"):
ctx.server.ws_server.close()
await ctx.server.ws_server.wait_closed()
except (KeyboardInterrupt, SystemExit):
with db_session:
room = Room.get(id=room_id)
# ensure the Room does not spin up again on its own, minute of safety buffer
room.last_activity = datetime.datetime.utcnow() - datetime.timedelta(minutes=1, seconds=room.timeout)
except Exception:
with db_session:
room = Room.get(id=room_id)
room.last_port = -1
# ensure the Room does not spin up again on its own, minute of safety buffer
room.last_activity = datetime.datetime.utcnow() - datetime.timedelta(minutes=1, seconds=room.timeout)
raise
finally:
rooms_shutting_down.put(room_id)
with db_session:
# ensure the Room does not spin up again on its own, minute of safety buffer
room = Room.get(id=room_id)
room.last_activity = datetime.datetime.utcnow() - \
datetime.timedelta(minutes=1, seconds=room.timeout)
del room
tear_down_logging(room_id)
logging.info(f"Shutting down room {room_id} on {name}.")
finally:
await asyncio.sleep(5)
rooms_shutting_down.put(room_id)
class Starter(threading.Thread):
_tasks: typing.List[asyncio.Future]
def __init__(self):
super().__init__()
self._tasks = []
def _done(self, task: asyncio.Future):
self._tasks.remove(task)
task.result()
def run(self):
while 1:
next_room = rooms_to_run.get(block=True, timeout=None)
asyncio.run_coroutine_threadsafe(start_room(next_room), loop)
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
starter.start()
loop.run_forever()
try:
loop.run_forever()
finally:
# save all tasks that want to be saved during shutdown
for task in asyncio.all_tasks(loop):
save: typing.Optional[typing.Callable[[], typing.Any]] = getattr(task, "save", None)
if save:
save()

View File

@@ -61,12 +61,7 @@ def download_slot_file(room_id, player_id: int):
else:
import io
if slot_data.game == "Minecraft":
from worlds.minecraft import mc_update_output
fname = f"AP_{app.jinja_env.filters['suuid'](room_id)}_P{slot_data.player_id}_{slot_data.player_name}.apmc"
data = mc_update_output(slot_data.data, server=app.config['HOST_ADDRESS'], port=room.last_port)
return send_file(io.BytesIO(data), as_attachment=True, download_name=fname)
elif slot_data.game == "Factorio":
if slot_data.game == "Factorio":
with zipfile.ZipFile(io.BytesIO(slot_data.data)) as zf:
for name in zf.namelist():
if name.endswith("info.json"):

View File

@@ -1,47 +1,45 @@
import concurrent.futures
import json
import os
import pickle
import random
import tempfile
import zipfile
from collections import Counter
from typing import Any, Dict, List, Optional, Union
from pickle import PicklingError
from typing import Any
from flask import flash, redirect, render_template, request, session, url_for
from pony.orm import commit, db_session
from BaseClasses import get_seed, seeddigits
from Generate import PlandoOptions, handle_name
from Generate import PlandoOptions, handle_name, mystery_argparse
from Main import main as ERmain
from Utils import __version__
from Utils import __version__, restricted_dumps, DaemonThreadPoolExecutor
from WebHostLib import app
from worlds.alttp.EntranceRandomizer import parse_arguments
from settings import ServerOptions, GeneratorOptions
from .check import get_yaml_data, roll_options
from .models import Generation, STATE_ERROR, STATE_QUEUED, Seed, UUID
from .upload import upload_zip_to_db
def get_meta(options_source: dict, race: bool = False) -> Dict[str, Union[List[str], Dict[str, Any]]]:
plando_options = {
options_source.get("plando_bosses", ""),
options_source.get("plando_items", ""),
options_source.get("plando_connections", ""),
options_source.get("plando_texts", "")
}
plando_options -= {""}
def get_meta(options_source: dict, race: bool = False) -> dict[str, list[str] | dict[str, Any]]:
plando_options: set[str] = set()
for substr in ("bosses", "items", "connections", "texts"):
if options_source.get(f"plando_{substr}", substr in GeneratorOptions.plando_options):
plando_options.add(substr)
server_options = {
"hint_cost": int(options_source.get("hint_cost", 10)),
"release_mode": options_source.get("release_mode", "goal"),
"remaining_mode": options_source.get("remaining_mode", "disabled"),
"collect_mode": options_source.get("collect_mode", "disabled"),
"item_cheat": bool(int(options_source.get("item_cheat", 1))),
"server_password": options_source.get("server_password", None),
"hint_cost": int(options_source.get("hint_cost", ServerOptions.hint_cost)),
"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)),
"countdown_mode": str(options_source.get("countdown_mode", ServerOptions.countdown_mode)),
"item_cheat": bool(int(options_source.get("item_cheat", not ServerOptions.disable_item_cheat))),
"server_password": str(options_source.get("server_password", None)),
}
generator_options = {
"spoiler": int(options_source.get("spoiler", 0)),
"race": race
"spoiler": int(options_source.get("spoiler", GeneratorOptions.spoiler)),
"race": race,
}
if race:
@@ -70,40 +68,59 @@ def generate(race=False):
flash(options)
else:
meta = get_meta(request.form, race)
results, gen_options = roll_options(options, set(meta["plando_options"]))
if any(type(result) == str for result in results.values()):
return render_template("checkResult.html", results=results)
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.")
elif len(gen_options) >= app.config["JOB_THRESHOLD"]:
gen = Generation(
options=pickle.dumps({name: vars(options) for name, options in gen_options.items()}),
# convert to json compatible
meta=json.dumps(meta),
state=STATE_QUEUED,
owner=session["_id"])
commit()
return redirect(url_for("wait_seed", seed=gen.id))
else:
try:
seed_id = gen_game({name: vars(options) for name, options in gen_options.items()},
meta=meta, owner=session["_id"].int)
except BaseException as e:
from .autolauncher import handle_generation_failure
handle_generation_failure(e)
return render_template("seedError.html", seed_error=(e.__class__.__name__ + ": " + str(e)))
return redirect(url_for("view_seed", seed=seed_id))
return start_generation(options, meta)
return render_template("generate.html", race=race, version=__version__)
def gen_game(gen_options: dict, meta: Optional[Dict[str, Any]] = None, owner=None, sid=None):
if not meta:
meta: Dict[str, Any] = {}
def format_exception(e: BaseException) -> str:
return f"{e.__class__.__name__}: {e}"
def start_generation(options: dict[str, dict | str], meta: dict[str, Any]):
results, gen_options = roll_options(options, set(meta["plando_options"]))
if any(type(result) == str for result in results.values()):
return render_template("checkResult.html", results=results)
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"]:
try:
gen = Generation(
options=restricted_dumps({name: vars(options) for name, options in gen_options.items()}),
# convert to json compatible
meta=json.dumps(meta),
state=STATE_QUEUED,
owner=session["_id"])
except PicklingError as e:
from .autolauncher import handle_generation_failure
handle_generation_failure(e)
meta["error"] = format_exception(e)
details = json.dumps(meta, indent=4).strip()
return render_template("seedError.html", seed_error=meta["error"], details=details)
commit()
return redirect(url_for("wait_seed", seed=gen.id))
else:
try:
seed_id = gen_game({name: vars(options) for name, options in gen_options.items()},
meta=meta, owner=session["_id"].int, timeout=app.config["JOB_TIME"])
except BaseException as e:
from .autolauncher import handle_generation_failure
handle_generation_failure(e)
meta["error"] = format_exception(e)
details = json.dumps(meta, indent=4).strip()
return render_template("seedError.html", seed_error=meta["error"], details=details)
return redirect(url_for("view_seed", seed=seed_id))
def gen_game(gen_options: dict, meta: dict[str, Any] | None = None, owner=None, sid=None, timeout: int|None = None):
if meta is None:
meta = {}
meta.setdefault("server_options", {}).setdefault("hint_cost", 10)
race = meta.setdefault("generator_options", {}).setdefault("race", False)
@@ -120,41 +137,47 @@ def gen_game(gen_options: dict, meta: Optional[Dict[str, Any]] = None, owner=Non
seedname = "W" + (f"{random.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits))
erargs = parse_arguments(['--multi', str(playercount)])
erargs.seed = seed
erargs.name = {x: "" for x in range(1, playercount + 1)} # only so it can be overwritten in mystery
erargs.spoiler = meta["generator_options"].get("spoiler", 0)
erargs.race = race
erargs.outputname = seedname
erargs.outputpath = target.name
erargs.teams = 1
erargs.plando_options = PlandoOptions.from_set(meta.setdefault("plando_options",
{"bosses", "items", "connections", "texts"}))
erargs.skip_prog_balancing = False
erargs.skip_output = False
args = mystery_argparse([]) # Just to set up the Namespace with defaults
args.multi = playercount
args.seed = seed
args.name = {x: "" for x in range(1, playercount + 1)} # only so it can be overwritten in mystery
args.spoiler = meta["generator_options"].get("spoiler", 0)
args.race = race
args.outputname = seedname
args.outputpath = target.name
args.teams = 1
args.plando_options = PlandoOptions.from_set(meta.setdefault("plando_options",
{"bosses", "items", "connections", "texts"}))
args.skip_prog_balancing = False
args.skip_output = False
args.spoiler_only = False
args.csv_output = False
args.sprite = dict.fromkeys(range(1, args.multi+1), None)
args.sprite_pool = dict.fromkeys(range(1, args.multi+1), None)
name_counter = Counter()
for player, (playerfile, settings) in enumerate(gen_options.items(), 1):
for k, v in settings.items():
if v is not None:
if hasattr(erargs, k):
getattr(erargs, k)[player] = v
if hasattr(args, k):
getattr(args, k)[player] = v
else:
setattr(erargs, k, {player: v})
setattr(args, k, {player: v})
if not erargs.name[player]:
erargs.name[player] = os.path.splitext(os.path.split(playerfile)[-1])[0]
erargs.name[player] = handle_name(erargs.name[player], player, name_counter)
if len(set(erargs.name.values())) != len(erargs.name):
raise Exception(f"Names have to be unique. Names: {Counter(erargs.name.values())}")
ERmain(erargs, seed, baked_server_options=meta["server_options"])
if not args.name[player]:
args.name[player] = os.path.splitext(os.path.split(playerfile)[-1])[0]
args.name[player] = handle_name(args.name[player], player, name_counter)
if len(set(args.name.values())) != len(args.name):
raise Exception(f"Names have to be unique. Names: {Counter(args.name.values())}")
ERmain(args, seed, baked_server_options=meta["server_options"])
return upload_to_db(target.name, sid, owner, race)
thread_pool = concurrent.futures.ThreadPoolExecutor(max_workers=1)
thread_pool = DaemonThreadPoolExecutor(max_workers=1)
thread = thread_pool.submit(task)
try:
return thread.result(app.config["JOB_TIME"])
return thread.result(timeout)
except concurrent.futures.TimeoutError as e:
if sid:
with db_session:
@@ -162,11 +185,14 @@ def gen_game(gen_options: dict, meta: Optional[Dict[str, Any]] = None, owner=Non
if gen is not None:
gen.state = STATE_ERROR
meta = json.loads(gen.meta)
meta["error"] = (
"Allowed time for Generation exceeded, please consider generating locally instead. " +
e.__class__.__name__ + ": " + str(e))
meta["error"] = ("Allowed time for Generation exceeded, " +
"please consider generating locally instead. " +
format_exception(e))
gen.meta = json.dumps(meta)
commit()
except (KeyboardInterrupt, SystemExit):
# don't update db, retry next time
raise
except BaseException as e:
if sid:
with db_session:
@@ -174,10 +200,15 @@ def gen_game(gen_options: dict, meta: Optional[Dict[str, Any]] = None, owner=Non
if gen is not None:
gen.state = STATE_ERROR
meta = json.loads(gen.meta)
meta["error"] = (e.__class__.__name__ + ": " + str(e))
meta["error"] = format_exception(e)
gen.meta = json.dumps(meta)
commit()
raise
finally:
# free resources claimed by thread pool, if possible
# NOTE: Timeout depends on the process being killed at some point
# since we can't actually cancel a running gen at the moment.
thread_pool.shutdown(wait=False, cancel_futures=True)
@app.route('/wait/<suuid:seed>')
@@ -191,7 +222,9 @@ def wait_seed(seed: UUID):
if not generation:
return "Generation not found."
elif generation.state == STATE_ERROR:
return render_template("seedError.html", seed_error=generation.meta)
meta = json.loads(generation.meta)
details = json.dumps(meta, indent=4).strip()
return render_template("seedError.html", seed_error=meta["error"], details=details)
return render_template("waitSeed.html", seed_id=seed_id)

View File

@@ -3,10 +3,10 @@ import threading
import json
from Utils import local_path, user_path
from worlds.alttp.Rom import Sprite
def update_sprites_lttp():
from worlds.alttp.Rom import Sprite
from tkinter import Tk
from LttPAdjuster import get_image_for_sprite
from LttPAdjuster import BackgroundTaskProgress
@@ -14,7 +14,7 @@ def update_sprites_lttp():
from LttPAdjuster import update_sprites
# Target directories
input_dir = user_path("data", "sprites", "alttpr")
input_dir = user_path("data", "sprites", "alttp", "remote")
output_dir = local_path("WebHostLib", "static", "generated") # TODO: move to user_path
os.makedirs(os.path.join(output_dir, "sprites"), exist_ok=True)

90
WebHostLib/markdown.py Normal file
View File

@@ -0,0 +1,90 @@
import re
from collections import Counter
import mistune
from werkzeug.utils import secure_filename
__all__ = [
"ImgUrlRewriteInlineParser",
'render_markdown',
]
class ImgUrlRewriteInlineParser(mistune.InlineParser):
relative_url_base: str
def __init__(self, relative_url_base: str, hard_wrap: bool = False) -> None:
super().__init__(hard_wrap)
self.relative_url_base = relative_url_base
@staticmethod
def _find_game_name_by_folder_name(name: str) -> str | None:
from worlds.AutoWorld import AutoWorldRegister
for world_name, world_type in AutoWorldRegister.world_types.items():
if world_type.__module__ == f"worlds.{name}":
return world_name
return None
def parse_link(self, m: re.Match[str], state: mistune.InlineState) -> int | None:
res = super().parse_link(m, state)
if res is not None and state.tokens and state.tokens[-1]["type"] == "image":
image_token = state.tokens[-1]
url: str = image_token["attrs"]["url"]
if not url.startswith("/") and not "://" in url:
# replace relative URL to another world's doc folder with the webhost folder layout
if url.startswith("../../") and "/docs/" in self.relative_url_base:
parts = url.split("/", 4)
if parts[2] != ".." and parts[3] == "docs":
game_name = self._find_game_name_by_folder_name(parts[2])
if game_name is not None:
url = "/".join(parts[1:2] + [secure_filename(game_name)] + parts[4:])
# change relative URL to point to deployment folder
url = f"{self.relative_url_base}/{url}"
image_token['attrs']['url'] = url
return res
def render_markdown(path: str, img_url_base: str | None = None) -> str:
markdown = mistune.create_markdown(
escape=False,
plugins=[
"strikethrough",
"footnotes",
"table",
"speedup",
],
)
heading_id_count: Counter[str] = Counter()
def heading_id(text: str) -> str:
nonlocal heading_id_count
# there is no good way to do this without regex
s = re.sub(r"[^\w\- ]", "", text.lower()).replace(" ", "-").strip("-")
n = heading_id_count[s]
heading_id_count[s] += 1
if n > 0:
s += f"-{n}"
return s
def id_hook(_: mistune.Markdown, state: mistune.BlockState) -> None:
for tok in state.tokens:
if tok["type"] == "heading" and tok["attrs"]["level"] < 4:
text = tok["text"]
assert isinstance(text, str)
unique_id = heading_id(text)
tok["attrs"]["id"] = unique_id
tok["text"] = f"<a href=\"#{unique_id}\">{text}</a>" # make header link to itself
markdown.before_render_hooks.append(id_hook)
if img_url_base:
markdown.inline = ImgUrlRewriteInlineParser(img_url_base)
with open(path, encoding="utf-8-sig") as f:
document = f.read()
html = markdown(document)
assert isinstance(html, str), "Unexpected mistune renderer in render_markdown"
return html

View File

@@ -1,27 +1,47 @@
import datetime
import os
from typing import List, Dict, Union
import warnings
from enum import StrEnum
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 worlds.AutoWorld import AutoWorldRegister, World
from . import app, cache
from .markdown import render_markdown
from .models import Seed, Room, Command, UUID, uuid4
from Utils import title_sorted
class WebWorldTheme(StrEnum):
DIRT = "dirt"
GRASS = "grass"
GRASS_FLOWERS = "grassFlowers"
ICE = "ice"
JUNGLE = "jungle"
OCEAN = "ocean"
PARTY_TIME = "partyTime"
STONE = "stone"
def get_world_theme(game_name: str) -> str:
if game_name not in AutoWorldRegister.world_types:
return "grass"
chosen_theme = AutoWorldRegister.world_types[game_name].web.theme
available_themes = [theme.value for theme in WebWorldTheme]
if chosen_theme not in available_themes:
warnings.warn(f"Theme '{chosen_theme}' for {game_name} not valid, switching to default 'grass' theme.")
return "grass"
return chosen_theme
def get_world_theme(game_name: str):
if game_name in AutoWorldRegister.world_types:
return AutoWorldRegister.world_types[game_name].web.theme
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
def get_visible_worlds() -> dict[str, type(World)]:
worlds = {}
for game, world in AutoWorldRegister.world_types.items():
if not world.hidden:
worlds[game] = world
return worlds
@app.errorhandler(404)
@@ -37,46 +57,107 @@ def start_playing():
return render_template(f"startPlaying.html")
# Game Info Pages
@app.route('/games/<string:game>/info/<string:lang>')
@cache.cached()
def game_info(game, lang):
return render_template('gameInfo.html', game=game, lang=lang, theme=get_world_theme(game))
"""Game Info Pages"""
try:
theme = get_world_theme(game)
secure_game_name = secure_filename(game)
lang = secure_filename(lang)
file_dir = os.path.join(app.static_folder, "generated", "docs", secure_game_name)
file_dir_url = url_for("static", filename=f"generated/docs/{secure_game_name}")
document = render_markdown(os.path.join(file_dir, f"{lang}_{secure_game_name}.md"), file_dir_url)
return render_template(
"markdown_document.html",
title=f"{game} Guide",
html_from_markdown=document,
theme=theme,
)
except FileNotFoundError:
return abort(404)
# List of supported games
@app.route('/games')
@cache.cached()
def games():
worlds = {}
for game, world in AutoWorldRegister.world_types.items():
if not world.hidden:
worlds[game] = world
return render_template("supportedGames.html", worlds=worlds)
"""List of supported games"""
return render_template("supportedGames.html", worlds=get_visible_worlds())
@app.route('/tutorial/<string:game>/<string:file>')
@cache.cached()
def tutorial(game: str, file: str):
try:
theme = get_world_theme(game)
secure_game_name = secure_filename(game)
file = secure_filename(file)
file_dir = os.path.join(app.static_folder, "generated", "docs", secure_game_name)
file_dir_url = url_for("static", filename=f"generated/docs/{secure_game_name}")
document = render_markdown(os.path.join(file_dir, f"{file}.md"), file_dir_url)
return render_template(
"markdown_document.html",
title=f"{game} Guide",
html_from_markdown=document,
theme=theme,
)
except FileNotFoundError:
return abort(404)
@app.route('/tutorial/<string:game>/<string:file>/<string:lang>')
@cache.cached()
def tutorial(game, file, lang):
return render_template("tutorial.html", game=game, file=file, lang=lang, theme=get_world_theme(game))
def tutorial_redirect(game: str, file: str, lang: str):
"""
Permanent redirect old tutorial URLs to new ones to keep search engines happy.
e.g. /tutorial/Archipelago/setup/en -> /tutorial/Archipelago/setup_en
"""
return redirect(url_for("tutorial", game=game, file=f"{file}_{lang}"), code=301)
@app.route('/tutorial/')
@cache.cached()
def tutorial_landing():
return render_template("tutorialLanding.html")
tutorials = {}
worlds = AutoWorldRegister.world_types
for world_name, world_type in worlds.items():
current_world = tutorials[world_name] = {}
for tutorial in world_type.web.tutorials:
current_tutorial = current_world.setdefault(tutorial.tutorial_name, {
"description": tutorial.description, "files": {}})
current_tutorial["files"][secure_filename(tutorial.file_name).rsplit(".", 1)[0]] = {
"authors": tutorial.authors,
"language": tutorial.language
}
worlds = dict(
title_sorted(
worlds.items(), key=lambda element: "\x00" if element[0] == "Archipelago" else worlds[element[0]].game
)
)
return render_template("tutorialLanding.html", worlds=worlds, tutorials=tutorials)
@app.route('/faq/<string:lang>/')
@cache.cached()
def faq(lang):
return render_template("faq.html", lang=lang)
def faq(lang: str):
document = render_markdown(os.path.join(app.static_folder, "assets", "faq", secure_filename(lang)+".md"))
return render_template(
"markdown_document.html",
title="Frequently Asked Questions",
html_from_markdown=document,
)
@app.route('/glossary/<string:lang>/')
@cache.cached()
def terms(lang):
return render_template("glossary.html", lang=lang)
def glossary(lang: str):
document = render_markdown(os.path.join(app.static_folder, "assets", "glossary", secure_filename(lang)+".md"))
return render_template(
"markdown_document.html",
title="Glossary",
html_from_markdown=document,
)
@app.route('/seed/<suuid:seed>')
@@ -97,49 +178,94 @@ 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)
with db_session:
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))
if now - room.last_activity > datetime.timedelta(minutes=1):
# we only set last_activity if needed, otherwise parallel access on /room will cause an internal server error
# due to "pony.orm.core.OptimisticCheckError: Object Room was updated outside of current transaction"
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) -> Tuple[str, int]:
if max_size == 0:
return "", 0
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), raw_size
except FileNotFoundError:
return "", 0
return render_template("hostRoom.html", room=room, should_refresh=should_refresh, get_log=get_log)
@app.route('/favicon.ico')

View File

@@ -1,83 +1,56 @@
import collections.abc
import os
import yaml
import requests
import json
import flask
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, abort
import Options
from Options import Visibility
from flask import redirect, render_template, request, Response
from worlds.AutoWorld import AutoWorldRegister
from Utils import local_path
from textwrap import dedent
from worlds.AutoWorld import AutoWorldRegister
from . import app, cache
from .generate import get_meta
from .misc import get_world_theme
def create():
def create() -> None:
target_folder = local_path("WebHostLib", "static", "generated")
yaml_folder = os.path.join(target_folder, "configs")
Options.generate_yaml_templates(yaml_folder)
def get_world_theme(game_name: str):
if game_name in AutoWorldRegister.world_types:
return AutoWorldRegister.world_types[game_name].web.theme
return 'grass'
def render_options_page(template: str, world_name: str, is_complex: bool = False):
def render_options_page(template: str, world_name: str, is_complex: bool = False) -> Union[Response, str]:
world = AutoWorldRegister.world_types[world_name]
if world.hidden or world.web.options_page is False:
return redirect("games")
visibility_flag = Options.Visibility.complex_ui if is_complex else Options.Visibility.simple_ui
option_groups = {option: option_group.name
for option_group in world.web.option_groups
for option in option_group.options}
ordered_groups = ["Game Options", *[group.name for group in world.web.option_groups]]
grouped_options = {group: {} for group in ordered_groups}
for option_name, option in world.options_dataclass.type_hints.items():
# Exclude settings from options pages if their visibility is disabled
if not is_complex and option.visibility < Visibility.simple_ui:
continue
if is_complex and option.visibility < Visibility.complex_ui:
continue
grouped_options[option_groups.get(option, "Game Options")][option_name] = option
start_collapsed = {"Game Options": False}
for group in world.web.option_groups:
start_collapsed[group.name] = group.start_collapsed
return render_template(
template,
world_name=world_name,
world=world,
option_groups=grouped_options,
option_groups=Options.get_option_groups(world, visibility_level=visibility_flag),
start_collapsed=start_collapsed,
issubclass=issubclass,
Options=Options,
theme=get_world_theme(world_name),
)
def generate_game(player_name: str, formatted_options: dict):
payload = {
"race": 0,
"hint_cost": 10,
"forfeit_mode": "auto",
"remaining_mode": "disabled",
"collect_mode": "goal",
"weights": {
player_name: formatted_options,
},
}
r = requests.post("https://archipelago.gg/api/generate", json=payload)
if 200 <= r.status_code <= 299:
response_data = r.json()
return redirect(response_data["url"])
else:
return r.text
def generate_game(options: Dict[str, Union[dict, str]]) -> Union[Response, str]:
from .generate import start_generation
return start_generation(options, get_meta({}))
def send_yaml(player_name: str, formatted_options: dict):
def send_yaml(player_name: str, formatted_options: dict) -> Response:
response = Response(yaml.dump(formatted_options, sort_keys=False))
response.headers["Content-Type"] = "text/yaml"
response.headers["Content-Disposition"] = f"attachment; filename={player_name}.yaml"
@@ -85,10 +58,26 @@ def send_yaml(player_name: str, formatted_options: dict):
@app.template_filter("dedent")
def filter_dedent(text: str):
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='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)
@@ -98,10 +87,34 @@ def test_ordered(obj):
@cache.cached()
def option_presets(game: str) -> Response:
world = AutoWorldRegister.world_types[game]
presets = {}
if world.web.options_presets:
presets = presets | world.web.options_presets
presets = {}
for preset_name, preset in world.web.options_presets.items():
presets[preset_name] = {}
for preset_option_name, preset_option in preset.items():
if preset_option == "random":
presets[preset_name][preset_option_name] = preset_option
continue
option = world.options_dataclass.type_hints[preset_option_name].from_any(preset_option)
if isinstance(option, Options.NamedRange) and isinstance(preset_option, str):
assert preset_option in option.special_range_names, \
f"Invalid preset value '{preset_option}' for '{preset_option_name}' in '{preset_name}'. " \
f"Expected {option.special_range_names.keys()} or {option.range_start}-{option.range_end}."
presets[preset_name][preset_option_name] = option.value
elif isinstance(option, (Options.Range, Options.OptionSet, Options.OptionList, Options.OptionCounter)):
presets[preset_name][preset_option_name] = option.value
elif isinstance(preset_option, str):
# Ensure the option value is valid for Choice and Toggle options
assert option.name_lookup[option.value] == preset_option, \
f"Invalid option value '{preset_option}' for '{preset_option_name}' in preset '{preset_name}'. " \
f"Values must not be resolved to a different option via option.from_text (or an alias)."
# Use the name of the option
presets[preset_name][preset_option_name] = option.current_key
else:
# Use the name of the option
presets[preset_name][preset_option_name] = option.current_key
class SetEncoder(json.JSONEncoder):
def default(self, obj):
@@ -111,7 +124,7 @@ def option_presets(game: str) -> Response:
return json.JSONEncoder.default(self, obj)
json_data = json.dumps(presets, cls=SetEncoder)
response = flask.Response(json_data)
response = Response(json_data)
response.headers["Content-Type"] = "application/json"
return response
@@ -124,7 +137,10 @@ def weighted_options_old():
@app.route("/games/<string:game>/weighted-options")
@cache.cached()
def weighted_options(game: str):
return render_options_page("weightedOptions/weightedOptions.html", game, is_complex=True)
try:
return render_options_page("weightedOptions/weightedOptions.html", game, is_complex=True)
except KeyError:
return abort(404)
@app.route("/games/<string:game>/generate-weighted-yaml", methods=["POST"])
@@ -134,7 +150,9 @@ def generate_weighted_yaml(game: str):
options = {}
for key, val in request.form.items():
if "||" not in key:
if val == "_ensure-empty-list":
options[key] = {}
elif "||" not in key:
if len(str(val)) == 0:
continue
@@ -169,7 +187,7 @@ def generate_weighted_yaml(game: str):
}
if intent_generate:
return generate_game(player_name, formatted_options)
return generate_game({player_name: formatted_options})
else:
return send_yaml(player_name, formatted_options)
@@ -179,7 +197,10 @@ def generate_weighted_yaml(game: str):
@app.route("/games/<string:game>/player-options")
@cache.cached()
def player_options(game: str):
return render_options_page("playerOptions/playerOptions.html", game, is_complex=False)
try:
return render_options_page("playerOptions/playerOptions.html", game, is_complex=False)
except KeyError:
return abort(404)
# YAML generator for player-options
@@ -188,24 +209,41 @@ def generate_yaml(game: str):
if request.method == "POST":
options = {}
intent_generate = False
for key, val in request.form.items(multi=True):
if key in options:
if val == "_ensure-empty-list":
options[key] = []
elif options.get(key):
if not isinstance(options[key], list):
options[key] = [options[key]]
options[key].append(val)
else:
options[key] = val
# Detect and build ItemDict options from their name pattern
for key, val in options.copy().items():
key_parts = key.rsplit("||", 2)
# Detect and build OptionCounter options from their name pattern
if key_parts[-1] == "qty":
if key_parts[0] not in options:
options[key_parts[0]] = {}
if val != "0":
if val and val != "0":
options[key_parts[0]][key_parts[1]] = int(val)
del options[key]
# Detect keys which end with -custom, indicating a TextChoice with a possible custom value
elif key_parts[-1].endswith("-custom"):
if val:
options[key_parts[-1][:-7]] = val
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-"):
@@ -243,7 +281,7 @@ def generate_yaml(game: str):
}
if intent_generate:
return generate_game(player_name, formatted_options)
return generate_game({player_name: formatted_options})
else:
return send_yaml(player_name, formatted_options)

View File

@@ -1,9 +1,13 @@
flask>=3.0.0
pony>=0.7.17
waitress>=2.1.2
Flask-Caching>=2.1.0
Flask-Compress>=1.14
Flask-Limiter>=3.5.0
bokeh>=3.1.1; python_version <= '3.8'
bokeh>=3.3.2; python_version >= '3.9'
markupsafe>=2.1.3
flask>=3.1.1
werkzeug>=3.1.3
pony>=0.7.19; python_version <= '3.12'
pony @ git+https://github.com/black-sliver/pony@7feb1221953b7fa4a6735466bf21a8b4d35e33ba#0.7.19; python_version >= '3.13'
waitress>=3.0.2
Flask-Caching>=2.3.0
Flask-Compress==1.18 # pkg_resources can't resolve the "backports.zstd" dependency of >1.18, breaking ModuleUpdate.py
Flask-Limiter>=3.12
bokeh>=3.6.3
markupsafe>=3.0.2
setproctitle>=1.3.5
mistune>=3.1.3
docutils>=0.22.2

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

@@ -22,8 +22,8 @@ players to rely upon each other to complete their game.
While a multiworld game traditionally requires all players to be playing the same game, a multi-game multiworld allows
players to randomize any of the supported games, and send items between them. This allows players of different
games to interact with one another in a single multiplayer environment. Archipelago supports multi-game multiworld.
Here is a list of our [Supported Games](https://archipelago.gg/games).
games to interact with one another in a single multiplayer environment. Archipelago supports multi-game multiworlds.
Here is a list of our [Supported Games](/games).
## Can I generate a single-player game with Archipelago?
@@ -33,7 +33,7 @@ play, open the Settings Page, pick your settings, and click Generate Game.
## How do I get started?
We have a [Getting Started](https://archipelago.gg/tutorial/Archipelago/setup/en) guide that will help you get the
We have a [Getting Started](/tutorial/Archipelago/setup/en) guide that will help you get the
software set up. You can use that guide to learn how to generate multiworlds. There are also basic instructions for
including multiple games, and hosting multiworlds on the website for ease and convenience.
@@ -57,7 +57,7 @@ their multiworld.
If a player must leave early, they can use Archipelago's release system. When a player releases their game, all items
in that game belonging to other players are sent out automatically. This allows other players to continue to play
uninterrupted. Here is a list of all of our [Server Commands](https://archipelago.gg/tutorial/Archipelago/commands/en).
uninterrupted. Here is a list of all of our [Server Commands](/tutorial/Archipelago/commands/en).
## What happens if an item is placed somewhere it is impossible to get?
@@ -66,7 +66,7 @@ is to ensure items necessary to complete the game will be accessible to the play
rules allowing certain items to be placed in normally unreachable locations, provided the player has indicated they are
comfortable exploiting certain glitches in the game.
## I want to add a game to the Archipelago randomizer. How do I do that?
## I want to develop a game implementation for Archipelago. How do I do that?
The best way to get started is to take a look at our code on GitHub:
[Archipelago GitHub Page](https://github.com/ArchipelagoMW/Archipelago).
@@ -77,4 +77,5 @@ 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 regarding development of a game implementation, feel free to ask in the **#ap-world-dev**
channel on our Discord.

View File

@@ -1,51 +0,0 @@
window.addEventListener('load', () => {
const gameInfo = document.getElementById('game-info');
new Promise((resolve, reject) => {
const ajax = new XMLHttpRequest();
ajax.onreadystatechange = () => {
if (ajax.readyState !== 4) { return; }
if (ajax.status === 404) {
reject("Sorry, this game's info page is not available in that language yet.");
return;
}
if (ajax.status !== 200) {
reject("Something went wrong while loading the info page.");
return;
}
resolve(ajax.responseText);
};
ajax.open('GET', `${window.location.origin}/static/generated/docs/${gameInfo.getAttribute('data-game')}/` +
`${gameInfo.getAttribute('data-lang')}_${gameInfo.getAttribute('data-game')}.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);
gameInfo.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);
gameInfo.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

@@ -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

@@ -6,6 +6,4 @@ window.addEventListener('load', () => {
document.getElementById('file-input').addEventListener('change', () => {
document.getElementById('host-game-form').submit();
});
adjustFooterHeight();
});

View File

@@ -1,49 +0,0 @@
window.addEventListener('load', () => {
// Reload tracker every 15 seconds
const url = window.location;
setInterval(() => {
const ajax = new XMLHttpRequest();
ajax.onreadystatechange = () => {
if (ajax.readyState !== 4) { return; }
// Create a fake DOM using the returned HTML
const domParser = new DOMParser();
const fakeDOM = domParser.parseFromString(ajax.responseText, 'text/html');
// Update item tracker
document.getElementById('inventory-table').innerHTML = fakeDOM.getElementById('inventory-table').innerHTML;
// Update only counters in the location-table
let counters = document.getElementsByClassName('counter');
const fakeCounters = fakeDOM.getElementsByClassName('counter');
for (let i = 0; i < counters.length; i++) {
counters[i].innerHTML = fakeCounters[i].innerHTML;
}
};
ajax.open('GET', url);
ajax.send();
}, 15000)
// Collapsible advancement sections
const categories = document.getElementsByClassName("location-category");
for (let i = 0; i < categories.length; i++) {
let hide_id = categories[i].id.split('-')[0];
if (hide_id == 'Total') {
continue;
}
categories[i].addEventListener('click', function() {
// Toggle the advancement list
document.getElementById(hide_id).classList.toggle("hide");
// Change text of the header
const tab_header = document.getElementById(hide_id+'-header').children[0];
const orig_text = tab_header.innerHTML;
let new_text;
if (orig_text.includes("▼")) {
new_text = orig_text.replace("▼", "▲");
}
else {
new_text = orig_text.replace("▲", "▼");
}
tab_header.innerHTML = new_text;
});
}
});

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"

View File

@@ -1,49 +1,43 @@
let updateSection = (sectionName, fakeDOM) => {
document.getElementById(sectionName).innerHTML = fakeDOM.getElementById(sectionName).innerHTML;
}
window.addEventListener('load', () => {
// Reload tracker every 15 seconds
const url = window.location;
setInterval(() => {
const ajax = new XMLHttpRequest();
ajax.onreadystatechange = () => {
if (ajax.readyState !== 4) { return; }
// Reload tracker every 60 seconds (sync'd)
const url = window.location;
// Note: This synchronization code is adapted from code in trackerCommon.js
const targetSecond = parseInt(document.getElementById('player-tracker').getAttribute('data-second')) + 3;
console.log("Target second of refresh: " + targetSecond);
// Create a fake DOM using the returned HTML
const domParser = new DOMParser();
const fakeDOM = domParser.parseFromString(ajax.responseText, 'text/html');
// Update item tracker
document.getElementById('inventory-table').innerHTML = fakeDOM.getElementById('inventory-table').innerHTML;
// Update only counters in the location-table
let counters = document.getElementsByClassName('counter');
const fakeCounters = fakeDOM.getElementsByClassName('counter');
for (let i = 0; i < counters.length; i++) {
counters[i].innerHTML = fakeCounters[i].innerHTML;
}
let getSleepTimeSeconds = () => {
// -40 % 60 is -40, which is absolutely wrong and should burn
var sleepSeconds = (((targetSecond - new Date().getSeconds()) % 60) + 60) % 60;
return sleepSeconds || 60;
};
ajax.open('GET', url);
ajax.send();
}, 15000)
// Collapsible advancement sections
const categories = document.getElementsByClassName("location-category");
for (let category of categories) {
let hide_id = category.id.split('_')[0];
if (hide_id === 'Total') {
continue;
}
category.addEventListener('click', function() {
// Toggle the advancement list
document.getElementById(hide_id).classList.toggle("hide");
// Change text of the header
const tab_header = document.getElementById(hide_id+'_header').children[0];
const orig_text = tab_header.innerHTML;
let new_text;
if (orig_text.includes("▼")) {
new_text = orig_text.replace("▼", "▲");
}
else {
new_text = orig_text.replace("▲", "▼");
}
tab_header.innerHTML = new_text;
});
}
let updateTracker = () => {
const ajax = new XMLHttpRequest();
ajax.onreadystatechange = () => {
if (ajax.readyState !== 4) { return; }
// Create a fake DOM using the returned HTML
const domParser = new DOMParser();
const fakeDOM = domParser.parseFromString(ajax.responseText, 'text/html');
// Update dynamic sections
updateSection('player-info', fakeDOM);
updateSection('section-filler', fakeDOM);
updateSection('section-terran', fakeDOM);
updateSection('section-zerg', fakeDOM);
updateSection('section-protoss', fakeDOM);
updateSection('section-nova', fakeDOM);
updateSection('section-kerrigan', fakeDOM);
updateSection('section-keys', fakeDOM);
updateSection('section-locations', fakeDOM);
};
ajax.open('GET', url);
ajax.send();
updater = setTimeout(updateTracker, getSleepTimeSeconds() * 1000);
};
window.updater = setTimeout(updateTracker, getSleepTimeSeconds() * 1000);
});

View File

@@ -1,47 +0,0 @@
const adjustFooterHeight = () => {
// If there is no footer on this page, do nothing
const footer = document.getElementById('island-footer');
if (!footer) { return; }
// If the body is taller than the window, also do nothing
if (document.body.offsetHeight > window.innerHeight) {
footer.style.marginTop = '0';
return;
}
// Add a margin-top to the footer to position it at the bottom of the screen
const sibling = footer.previousElementSibling;
const margin = (window.innerHeight - sibling.offsetTop - sibling.offsetHeight - footer.offsetHeight);
if (margin < 1) {
footer.style.marginTop = '0';
return;
}
footer.style.marginTop = `${margin}px`;
};
const adjustHeaderWidth = () => {
// If there is no header, do nothing
const header = document.getElementById('base-header');
if (!header) { return; }
const tempDiv = document.createElement('div');
tempDiv.style.width = '100px';
tempDiv.style.height = '100px';
tempDiv.style.overflow = 'scroll';
tempDiv.style.position = 'absolute';
tempDiv.style.top = '-500px';
document.body.appendChild(tempDiv);
const scrollbarWidth = tempDiv.offsetWidth - tempDiv.clientWidth;
document.body.removeChild(tempDiv);
const documentRoot = document.compatMode === 'BackCompat' ? document.body : document.documentElement;
const margin = (documentRoot.scrollHeight > documentRoot.clientHeight) ? 0-scrollbarWidth : 0;
document.getElementById('base-header-right').style.marginRight = `${margin}px`;
};
window.addEventListener('load', () => {
window.addEventListener('resize', adjustFooterHeight);
window.addEventListener('resize', adjustHeaderWidth);
adjustFooterHeight();
adjustHeaderWidth();
});

View File

@@ -27,7 +27,7 @@ const adjustTableHeight = () => {
* @returns {string}
*/
const secondsToHours = (seconds) => {
let hours = Math.floor(seconds / 3600);
let hours = Math.floor(seconds / 3600);
let minutes = Math.floor((seconds - (hours * 3600)) / 60).toString().padStart(2, '0');
return `${hours}:${minutes}`;
};
@@ -38,18 +38,18 @@ window.addEventListener('load', () => {
info: false,
dom: "t",
stateSave: true,
stateSaveCallback: function(settings, data) {
stateSaveCallback: function (settings, data) {
delete data.search;
localStorage.setItem(`DataTables_${settings.sInstance}_/tracker`, JSON.stringify(data));
},
stateLoadCallback: function(settings) {
stateLoadCallback: function (settings) {
return JSON.parse(localStorage.getItem(`DataTables_${settings.sInstance}_/tracker`));
},
footerCallback: function(tfoot, data, start, end, display) {
footerCallback: function (tfoot, data, start, end, display) {
if (tfoot) {
const activityData = this.api().column('lastActivity:name').data().toArray().filter(x => !isNaN(x));
Array.from(tfoot?.children).find(td => td.classList.contains('last-activity')).innerText =
(activityData.length) ? secondsToHours(Math.min(...activityData)) : 'None';
(activityData.length) ? secondsToHours(Math.min(...activityData)) : 'None';
}
},
columnDefs: [
@@ -123,49 +123,64 @@ window.addEventListener('load', () => {
event.preventDefault();
}
});
const tracker = document.getElementById('tracker-wrapper').getAttribute('data-tracker');
const target_second = document.getElementById('tracker-wrapper').getAttribute('data-second') + 3;
const target_second = parseInt(document.getElementById('tracker-wrapper').getAttribute('data-second')) + 3;
console.log("Target second of refresh: " + target_second);
function getSleepTimeSeconds(){
function getSleepTimeSeconds() {
// -40 % 60 is -40, which is absolutely wrong and should burn
var sleepSeconds = (((target_second - new Date().getSeconds()) % 60) + 60) % 60;
return sleepSeconds || 60;
}
let update_on_view = false;
const update = () => {
const target = $("<div></div>");
console.log("Updating Tracker...");
target.load(location.href, function (response, status) {
if (status === "success") {
target.find(".table").each(function (i, new_table) {
const new_trs = $(new_table).find("tbody>tr");
const footer_tr = $(new_table).find("tfoot>tr");
const old_table = tables.eq(i);
const topscroll = $(old_table.settings()[0].nScrollBody).scrollTop();
const leftscroll = $(old_table.settings()[0].nScrollBody).scrollLeft();
old_table.clear();
if (footer_tr.length) {
$(old_table.table).find("tfoot").html(footer_tr);
}
old_table.rows.add(new_trs);
old_table.draw();
$(old_table.settings()[0].nScrollBody).scrollTop(topscroll);
$(old_table.settings()[0].nScrollBody).scrollLeft(leftscroll);
});
$("#multi-stream-link").replaceWith(target.find("#multi-stream-link"));
} else {
console.log("Failed to connect to Server, in order to update Table Data.");
console.log(response);
}
})
setTimeout(update, getSleepTimeSeconds()*1000);
if (document.hidden) {
console.log("Document reporting as not visible, not updating Tracker...");
update_on_view = true;
} else {
update_on_view = false;
const target = $("<div></div>");
console.log("Updating Tracker...");
target.load(location.href, function (response, status) {
if (status === "success") {
target.find(".table").each(function (i, new_table) {
const new_trs = $(new_table).find("tbody>tr");
const footer_tr = $(new_table).find("tfoot>tr");
const old_table = tables.eq(i);
const topscroll = $(old_table.settings()[0].nScrollBody).scrollTop();
const leftscroll = $(old_table.settings()[0].nScrollBody).scrollLeft();
old_table.clear();
if (footer_tr.length) {
$(old_table.table).find("tfoot").html(footer_tr);
}
old_table.rows.add(new_trs);
old_table.draw();
$(old_table.settings()[0].nScrollBody).scrollTop(topscroll);
$(old_table.settings()[0].nScrollBody).scrollLeft(leftscroll);
});
$("#multi-stream-link").replaceWith(target.find("#multi-stream-link"));
} else {
console.log("Failed to connect to Server, in order to update Table Data.");
console.log(response);
}
})
}
updater = setTimeout(update, getSleepTimeSeconds() * 1000);
}
setTimeout(update, getSleepTimeSeconds()*1000);
let updater = setTimeout(update, getSleepTimeSeconds() * 1000);
window.addEventListener('resize', () => {
adjustTableHeight();
tables.draw();
});
window.addEventListener('visibilitychange', () => {
if (!document.hidden && update_on_view) {
console.log("Page became visible, tracker should be refreshed.");
clearTimeout(updater);
update();
}
});
adjustTableHeight();
});

View File

@@ -1,58 +0,0 @@
window.addEventListener('load', () => {
const tutorialWrapper = document.getElementById('tutorial-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/generated/docs/` +
`${tutorialWrapper.getAttribute('data-game')}/${tutorialWrapper.getAttribute('data-file')}_` +
`${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);
showdown.setOption('disableForced4SpacesIndentedSublists', true);
tutorialWrapper.innerHTML += (new showdown.Converter()).makeHtml(results);
adjustHeaderWidth();
const title = document.querySelector('h1')
if (title) {
document.title = title.textContent;
}
// 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}/tutorial">here</a> to return to safety.</h3>`;
});
});

View File

@@ -1,81 +0,0 @@
const showError = () => {
const tutorial = document.getElementById('tutorial-landing');
document.getElementById('page-title').innerText = 'This page is out of logic!';
tutorial.removeChild(document.getElementById('loading'));
const userMessage = document.createElement('h3');
const homepageLink = document.createElement('a');
homepageLink.innerText = 'Click here';
homepageLink.setAttribute('href', '/');
userMessage.append(homepageLink);
userMessage.append(' to go back to safety!');
tutorial.append(userMessage);
};
window.addEventListener('load', () => {
const ajax = new XMLHttpRequest();
ajax.onreadystatechange = () => {
if (ajax.readyState !== 4) { return; }
const tutorialDiv = document.getElementById('tutorial-landing');
if (ajax.status !== 200) { return showError(); }
try {
const games = JSON.parse(ajax.responseText);
games.forEach((game) => {
const gameTitle = document.createElement('h2');
gameTitle.innerText = game.gameTitle;
gameTitle.id = `${encodeURIComponent(game.gameTitle)}`;
tutorialDiv.appendChild(gameTitle);
game.tutorials.forEach((tutorial) => {
const tutorialName = document.createElement('h3');
tutorialName.innerText = tutorial.name;
tutorialDiv.appendChild(tutorialName);
const tutorialDescription = document.createElement('p');
tutorialDescription.innerText = tutorial.description;
tutorialDiv.appendChild(tutorialDescription);
const intro = document.createElement('p');
intro.innerText = 'This guide is available in the following languages:';
tutorialDiv.appendChild(intro);
const fileList = document.createElement('ul');
tutorial.files.forEach((file) => {
const listItem = document.createElement('li');
const anchor = document.createElement('a');
anchor.innerText = file.language;
anchor.setAttribute('href', `${window.location.origin}/tutorial/${file.link}`);
listItem.appendChild(anchor);
listItem.append(' by ');
for (let author of file.authors) {
listItem.append(author);
if (file.authors.indexOf(author) !== (file.authors.length -1)) {
listItem.append(', ');
}
}
fileList.appendChild(listItem);
});
tutorialDiv.appendChild(fileList);
});
});
tutorialDiv.removeChild(document.getElementById('loading'));
} catch (error) {
showError();
console.error(error);
}
// Check if we are on an anchor when coming in, and scroll to it.
const hash = window.location.hash;
if (hash) {
const offset = 128; // To account for navbar banner at top of page.
window.scrollTo(0, 0);
const rect = document.getElementById(hash.slice(1)).getBoundingClientRect();
window.scrollTo(rect.left, rect.top - offset);
}
};
ajax.open('GET', `${window.location.origin}/static/generated/tutorials.json`, true);
ajax.send();
});

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

Some files were not shown because too many files have changed in this diff Show More