mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-23 11:03:20 -07:00
Merge branch 'ArchipelagoMW:main' into main
This commit is contained in:
@@ -45,6 +45,9 @@
|
||||
# ChecksFinder
|
||||
/worlds/checksfinder/ @SunCatMC
|
||||
|
||||
# Civilization VI
|
||||
/worlds/civ6/ @hesto2
|
||||
|
||||
# Clique
|
||||
/worlds/clique/ @ThePhar
|
||||
|
||||
@@ -211,6 +214,9 @@
|
||||
# Wargroove
|
||||
/worlds/wargroove/ @FlySniper
|
||||
|
||||
# The Wind Waker
|
||||
/worlds/tww/ @tanjo3
|
||||
|
||||
# The Witness
|
||||
/worlds/witness/ @NewSoupVi @blastron
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# Adding Games
|
||||
|
||||
Like all contributions to Archipelago, New Game implementations should follow the [Contributing](/docs/contributing.md)
|
||||
guide.
|
||||
|
||||
Adding a new game to Archipelago has two major parts:
|
||||
|
||||
* Game Modification to communicate with Archipelago server (hereafter referred to as "client")
|
||||
@@ -13,30 +16,51 @@ it will not be detailed here.
|
||||
|
||||
The client is an intermediary program between the game and the Archipelago server. This can either be a direct
|
||||
modification to the game, an external program, or both. This can be implemented in nearly any modern language, but it
|
||||
must fulfill a few requirements in order to function as expected. The specific requirements the game client must follow
|
||||
to behave as expected are:
|
||||
must fulfill a few requirements in order to function as expected. Libraries for most modern languages and the spec for
|
||||
various packets can be found in the [network protocol](/docs/network%20protocol.md) API reference document.
|
||||
|
||||
### Hard Requirements
|
||||
|
||||
In order for the game client to behave as expected, it must be able to perform these functions:
|
||||
|
||||
* Handle both secure and unsecure websocket connections
|
||||
* Detect and react when a location has been "checked" by the player by sending a network packet to the server
|
||||
* Receive and parse network packets when the player receives an item from the server, and reward it to the player on
|
||||
demand
|
||||
* **Any** of your items can be received any number of times, up to and far surpassing those that the game might
|
||||
normally expect from features such as starting inventory, item link replacement, or item cheating
|
||||
* Players and the admin can cheat items to the player at any time with a server command, and these items may not have
|
||||
a player or location attributed to them
|
||||
* Reconnect if the connection is unstable and lost while playing
|
||||
* Be able to change the port for saved connection info
|
||||
* Rooms hosted on the website attempt to reserve their port, but since there are a limited number of ports, this
|
||||
privilege can be lost, requiring the room to be moved to a new port
|
||||
* Reconnect if the connection is unstable and lost while playing
|
||||
* Keep an index for items received in order to resync. The ItemsReceived Packets are a single list with guaranteed
|
||||
order.
|
||||
* Receive items that were sent to the player while they were not connected to the server
|
||||
* The player being able to complete checks while offline and sending them when reconnecting is a good bonus, but not
|
||||
strictly required
|
||||
privilege can be lost, requiring the room to be moved to a new port
|
||||
* Send a status update packet alerting the server that the player has completed their goal
|
||||
|
||||
Libraries for most modern languages and the spec for various packets can be found in the
|
||||
[network protocol](/docs/network%20protocol.md) API reference document.
|
||||
Regarding items and locations, the game client must be able to handle these tasks:
|
||||
|
||||
#### Location Handling
|
||||
|
||||
Send a network packet to the server when it detects a location has been "checked" by the player in-game.
|
||||
|
||||
* If actions were taken in game that would usually trigger a location check, and those actions can only ever be taken
|
||||
once, but the client was not connected when they happened: The client must send those location checks on connection
|
||||
so that they are not permanently lost, e.g. by reading flags in the game state or save file.
|
||||
|
||||
#### Item Handling
|
||||
|
||||
Receive and parse network packets from the server when the player receives an item.
|
||||
|
||||
* It must reward items to the player on demand, as items can come from other players at any time.
|
||||
* It must be able to reward copies of an item, up to and beyond the number the game normally expects. This may happen
|
||||
due to features such as starting inventory, item link replacement, admin commands, or item cheating. **Any** of
|
||||
your items can be received **any** number of times.
|
||||
* Admins and players may use server commands to create items without a player or location attributed to them. The
|
||||
client must be able to handle these items.
|
||||
* It must keep an index for items received in order to resync. The ItemsReceived Packets are a single list with a
|
||||
guaranteed order.
|
||||
* It must be able to receive items that were sent to the player while they were not connected to the server.
|
||||
|
||||
### Encouraged Features
|
||||
|
||||
These are "nice to have" features for a client, but they are not strictly required. It is encouraged to add them
|
||||
if possible.
|
||||
|
||||
* If your client appears in the Archipelago Launcher, you may define an icon for it that differentiates it from
|
||||
other clients. The icon size is 48x48 pixels, but smaller or larger images will scale to that size.
|
||||
|
||||
## World
|
||||
|
||||
@@ -44,35 +68,94 @@ The world is your game integration for the Archipelago generator, webhost, and m
|
||||
information necessary for creating the items and locations to be randomized, the logic for item placement, the
|
||||
datapackage information so other game clients can recognize your game data, and documentation. Your world must be
|
||||
written as a Python package to be loaded by Archipelago. This is currently done by creating a fork of the Archipelago
|
||||
repository and creating a new world package in `/worlds/`. A bare minimum world implementation must satisfy the
|
||||
following requirements:
|
||||
repository and creating a new world package in `/worlds/`.
|
||||
|
||||
* A folder within `/worlds/` that contains an `__init__.py`
|
||||
* A `World` subclass where you create your world and define all of its rules
|
||||
* A unique game name
|
||||
* For webhost documentation and behaviors, a `WebWorld` subclass that must be instantiated in the `World` class
|
||||
definition
|
||||
* The game_info doc must follow the format `{language_code}_{game_name}.md`
|
||||
The base World class can be found in [AutoWorld](/worlds/AutoWorld.py). Methods available for your world to call
|
||||
during generation can be found in [BaseClasses](/BaseClasses.py) and [Fill](/Fill.py). Some examples and documentation
|
||||
regarding the API can be found in the [world api doc](/docs/world%20api.md). Before publishing, make sure to also
|
||||
check out [world maintainer.md](/docs/world%20maintainer.md).
|
||||
|
||||
### Hard Requirements
|
||||
|
||||
A bare minimum world implementation must satisfy the following requirements:
|
||||
|
||||
* It has a folder with the name of your game (or an abbreviation) under `/worlds/`
|
||||
* The `/worlds/{game}` folder contains an `__init__.py`
|
||||
* Any subfolders within `/worlds/{game}` that contain `*.py` files also contain an `__init__.py` for frozen build
|
||||
packaging
|
||||
* The game folder has at least one game_info doc named with follow the format `{language_code}_{game_name}.md`
|
||||
* The game folder has at least one setup doc
|
||||
* There must be a `World` subclass in your game folder (typically in `/worlds/{game}/__init__.py`) where you create
|
||||
your world and define all of its rules and features
|
||||
|
||||
Within the `World` subclass you should also have:
|
||||
|
||||
* A [unique game name](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L260)
|
||||
* An [instance](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L295) of a `WebWorld`
|
||||
subclass for webhost documentation and behaviors
|
||||
* In your `WebWorld`, if you wrote a game_info doc in more than one language, override the list of
|
||||
[game info languages](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L210) with the
|
||||
ones you include.
|
||||
* In your `WebWorld`, override the list of
|
||||
[tutorials](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L213) with each tutorial
|
||||
or setup doc you included in the game folder.
|
||||
* A mapping for items and locations defining their names and ids for clients to be able to identify them. These are
|
||||
`item_name_to_id` and `location_name_to_id`, respectively.
|
||||
* Create an item when `create_item` is called both by your code and externally
|
||||
* An `options_dataclass` defining the options players have available to them
|
||||
* A `Region` for your player with the name "Menu" to start from
|
||||
* Create a non-zero number of locations and add them to your regions
|
||||
* Create a non-zero number of items **equal** to the number of locations and add them to the multiworld itempool
|
||||
* All items submitted to the multiworld itempool must not be manually placed by the World. If you need to place specific
|
||||
items, there are multiple ways to do so, but they should not be added to the multiworld itempool.
|
||||
`item_name_to_id` and `location_name_to_id`, respectively.
|
||||
* An implementation of `create_item` that can create an item when called by either your code or by another process
|
||||
within Archipelago
|
||||
* At least one `Region` for your player to start from (i.e. the Origin Region)
|
||||
* The default name of this region is "Menu" but you may configure a different name with
|
||||
[origin_region_name](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L298-L299)
|
||||
* A non-zero number of locations, added to your regions
|
||||
* A non-zero number of items **equal** to the number of locations, added to the multiworld itempool
|
||||
* In rare cases, there may be 0-location-0-item games, but this is extremely atypical.
|
||||
* A set
|
||||
[completion condition](https://github.com/ArchipelagoMW/Archipelago/blob/main/BaseClasses.py#L77) (aka "goal") for
|
||||
the player.
|
||||
* Use your player as the index (`multiworld.completion_condition[player]`) for your world's completion goal.
|
||||
|
||||
Notable caveats:
|
||||
* The "Menu" region will always be considered the "start" for the player
|
||||
* The "Menu" region is *always* considered accessible; i.e. the player is expected to always be able to return to the
|
||||
### Encouraged Features
|
||||
|
||||
These are "nice to have" features for a world, but they are not strictly required. It is encouraged to add them
|
||||
if possible.
|
||||
|
||||
* An implementation of
|
||||
[get_filler_item_name](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L473)
|
||||
* By default, this function chooses any item name from `item_name_to_id`, so you want to limit it to only the true
|
||||
filler items.
|
||||
* An `options_dataclass` defining the options players have available to them
|
||||
* This should be accompanied by a type hint for `options` with the same class name
|
||||
* A [bug report page](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L220)
|
||||
* A list of [option groups](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L226)
|
||||
for better organization on the webhost
|
||||
* A dictionary of [options presets](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L223)
|
||||
for player convenience
|
||||
* A dictionary of [item name groups](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L273)
|
||||
for player convenience
|
||||
* A dictionary of
|
||||
[location name groups](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L276)
|
||||
for player convenience
|
||||
* Other games may also benefit from your name group dictionaries for hints, features, etc.
|
||||
|
||||
### Discouraged or Prohibited Behavior
|
||||
|
||||
These are behaviors or implementations that are known to cause various issues. Some of these points have notable
|
||||
workarounds or preferred methods which should be used instead:
|
||||
|
||||
* All items submitted to the multiworld itempool must not be manually placed by the World.
|
||||
* If you need to place specific items, there are multiple ways to do so, but they should not be added to the
|
||||
multiworld itempool.
|
||||
* It is not allowed to use `eval` for most reasons, chiefly due to security concerns.
|
||||
* It is discouraged to use PyYAML (i.e. `yaml.load`) directly due to security concerns.
|
||||
* When possible, use `Utils.parse_yaml` instead, as this defaults to the safe loader and the faster C parser.
|
||||
* When submitting regions or items to the multiworld (`multiworld.regions` and `multiworld.itempool` respectively),
|
||||
do **not** use `=` as this will overwrite all elements for all games in the seed.
|
||||
* Instead, use `append`, `extend`, or `+=`.
|
||||
|
||||
### Notable Caveats
|
||||
|
||||
* The Origin Region will always be considered the "start" for the player
|
||||
* The Origin Region is *always* considered accessible; i.e. the player is expected to always be able to return to the
|
||||
start of the game from anywhere
|
||||
* When submitting regions or items to the multiworld (multiworld.regions and multiworld.itempool respectively), use
|
||||
`append`, `extend`, or `+=`. **Do not use `=`**
|
||||
* Regions are simply containers for locations that share similar access rules. They do not have to map to
|
||||
concrete, physical areas within your game and can be more abstract like tech trees or a questline.
|
||||
|
||||
The base World class can be found in [AutoWorld](/worlds/AutoWorld.py). Methods available for your world to call during
|
||||
generation can be found in [BaseClasses](/BaseClasses.py) and [Fill](/Fill.py). Some examples and documentation
|
||||
regarding the API can be found in the [world api doc](/docs/world%20api.md).
|
||||
Before publishing, make sure to also check out [world maintainer.md](/docs/world%20maintainer.md).
|
||||
|
||||
@@ -66,3 +66,22 @@ The reason entrance access rules using `location.can_reach` and `entrance.can_re
|
||||
We recognize it can feel like a trap since it will not alert you when you are missing an indirect condition, and that some games have very complex access rules.
|
||||
As of [PR #3682 (Core: Region handling customization)](https://github.com/ArchipelagoMW/Archipelago/pull/3682) being merged, it is possible for a world to opt out of indirect conditions entirely, instead using the system of checking each entrance whenever a region has been reached, although this does come with a performance cost.
|
||||
Opting out of using indirect conditions should only be used by games that *really* need it. For most games, it should be reasonable to know all entrance → region dependencies, making indirect conditions preferred because they are much faster.
|
||||
|
||||
---
|
||||
|
||||
### I uploaded the generated output of my world to the webhost and webhost is erroring on corrupted multidata
|
||||
|
||||
The error `Could not load multidata. File may be corrupted or incompatible.` occurs when uploading a locally generated
|
||||
file where there is an issue with the multidata contained within it. It may come with a description like
|
||||
`(No module named 'worlds.myworld')` or `(global 'worlds.myworld.names.ItemNames' is forbidden)`
|
||||
|
||||
Pickling is a way to compress python objects such that they can be decompressed and be used to rebuild the
|
||||
python objects. This means that if one of your custom class instances ends up in the multidata, the server would not
|
||||
be able to load that custom class to decompress the data, which can fail either because the custom class is unknown
|
||||
(because it cannot load your world module) or the class it's attempting to import to decompress is deemed unsafe.
|
||||
|
||||
Common situations where this can happen include:
|
||||
* Using Option instances directly in slot_data. Ex: using `options.option_name` instead of `options.option_name.value`.
|
||||
Also, consider using the `options.as_dict("option_name", "option_two")` helper.
|
||||
* Using enums as Location/Item names in the datapackage. When building out `location_name_to_id` and `item_name_to_id`,
|
||||
make sure that you are not using your enum class for either the names or ids in these mappings.
|
||||
|
||||
@@ -47,6 +47,9 @@ Packets are simple JSON lists in which any number of ordered network commands ca
|
||||
|
||||
An object can contain the "class" key, which will tell the content data type, such as "Version" in the following example.
|
||||
|
||||
Websocket connections should support per-message compression. Uncompressed connections are deprecated and may stop
|
||||
working in the future.
|
||||
|
||||
Example:
|
||||
```javascript
|
||||
[{"cmd": "RoomInfo", "version": {"major": 0, "minor": 1, "build": 3, "class": "Version"}, "tags": ["WebHost"], ... }]
|
||||
@@ -360,11 +363,11 @@ An enumeration containing the possible hint states.
|
||||
```python
|
||||
import enum
|
||||
class HintStatus(enum.IntEnum):
|
||||
HINT_FOUND = 0 # The location has been collected. Status cannot be changed once found.
|
||||
HINT_UNSPECIFIED = 1 # The receiving player has not specified any status
|
||||
HINT_UNSPECIFIED = 0 # The receiving player has not specified any status
|
||||
HINT_NO_PRIORITY = 10 # The receiving player has specified that the item is unneeded
|
||||
HINT_AVOID = 20 # The receiving player has specified that the item is detrimental
|
||||
HINT_PRIORITY = 30 # The receiving player has specified that the item is needed
|
||||
HINT_FOUND = 40 # The location has been collected. Status cannot be changed once found.
|
||||
```
|
||||
- Hints for items with `ItemClassification.trap` default to `HINT_AVOID`.
|
||||
- Hints created with `LocationScouts`, `!hint_location`, or similar (hinting a location) default to `HINT_UNSPECIFIED`.
|
||||
@@ -467,7 +470,7 @@ The following operations can be applied to a datastorage key
|
||||
| right_shift | Applies a bitwise right-shift to the current value of the key by `value`. |
|
||||
| remove | List only: removes the first instance of `value` found in the list. |
|
||||
| pop | List or Dict: for lists it will remove the index of the `value` given. for dicts it removes the element with the specified key of `value`. |
|
||||
| update | Dict only: Updates the dictionary with the specified elements given in `value` creating new keys, or updating old ones if they previously existed. |
|
||||
| update | List or Dict: Adds the elements of `value` to the container if they weren't already present. In the case of a Dict, already present keys will have their corresponding values updated. |
|
||||
|
||||
### SetNotify
|
||||
Used to register your current session for receiving all [SetReply](#SetReply) packages of certain keys to allow your client to keep track of changes.
|
||||
@@ -530,9 +533,9 @@ In JSON this may look like:
|
||||
{"item": 3, "location": 3, "player": 3, "flags": 0}
|
||||
]
|
||||
```
|
||||
`item` is the item id of the item. Item ids are only supported in the range of [-2<sup>53</sup>, 2<sup>53</sup> - 1], with anything ≤ 0 reserved for Archipelago use.
|
||||
`item` is the item id of the item. Item ids are only supported in the range of [-2<sup>53</sup> + 1, 2<sup>53</sup> - 1], with anything ≤ 0 reserved for Archipelago use.
|
||||
|
||||
`location` is the location id of the item inside the world. Location ids are only supported in the range of [-2<sup>53</sup>, 2<sup>53</sup> - 1], with anything ≤ 0 reserved for Archipelago use.
|
||||
`location` is the location id of the item inside the world. Location ids are only supported in the range of [-2<sup>53</sup> + 1, 2<sup>53</sup> - 1], with anything ≤ 0 reserved for Archipelago use.
|
||||
|
||||
`player` is the player slot of the world the item is located in, except when inside an [LocationInfo](#LocationInfo) Packet then it will be the slot of the player to receive the item
|
||||
|
||||
@@ -745,6 +748,7 @@ Tags are represented as a list of strings, the common client tags follow:
|
||||
| HintGame | Indicates the client is a hint game, made to send hints instead of locations. Special join/leave message,¹ `game` is optional.² |
|
||||
| Tracker | Indicates the client is a tracker, made to track instead of sending locations. Special join/leave message,¹ `game` is optional.² |
|
||||
| TextOnly | Indicates the client is a basic client, made to chat instead of sending locations. Special join/leave message,¹ `game` is optional.² |
|
||||
| NoText | Indicates the client does not want to receive text messages, improving performance if not needed. |
|
||||
|
||||
¹: When connecting or disconnecting, the chat message shows e.g. "tracking".\
|
||||
²: Allows `game` to be empty or null in [Connect](#connect). Game and version validation will then be skipped.
|
||||
@@ -752,8 +756,8 @@ Tags are represented as a list of strings, the common client tags follow:
|
||||
### DeathLink
|
||||
A special kind of Bounce packet that can be supported by any AP game. It targets the tag "DeathLink" and carries the following data:
|
||||
|
||||
| Name | Type | Notes |
|
||||
|--------|-------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| time | float | Unix Time Stamp of time of death. |
|
||||
| cause | str | Optional. Text to explain the cause of death. When provided, or checked, this should contain the player name, ex. "Berserker was run over by a train." |
|
||||
| source | str | Name of the player who first died. Can be a slot name, but can also be a name from within a multiplayer game. |
|
||||
| Name | Type | Notes |
|
||||
|--------|-------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| time | float | Unix Time Stamp of time of death. |
|
||||
| cause | str | Optional. Text to explain the cause of death. When provided, or checked, if the string is non-empty, it should contain the player name, ex. "Berserker was run over by a train." |
|
||||
| source | str | Name of the player who first died. Can be a slot name, but can also be a name from within a multiplayer game. |
|
||||
|
||||
@@ -73,15 +73,47 @@ When tests are run, this class will create a multiworld with a single player hav
|
||||
generic tests, as well as the new custom test. Each test method definition will create its own separate solo multiworld
|
||||
that will be cleaned up after. If you don't want to run the generic tests on a base, `run_default_tests` can be
|
||||
overridden. For more information on what methods are available to your class, check the
|
||||
[WorldTestBase definition](/test/bases.py#L104).
|
||||
[WorldTestBase definition](/test/bases.py#L106).
|
||||
|
||||
#### Alternatives to WorldTestBase
|
||||
|
||||
Unit tests can also be created using [TestBase](/test/bases.py#L14) or
|
||||
Unit tests can also be created using [TestBase](/test/bases.py#L16) or
|
||||
[unittest.TestCase](https://docs.python.org/3/library/unittest.html#unittest.TestCase) depending on your use case. These
|
||||
may be useful for generating a multiworld under very specific constraints without using the generic world setup, or for
|
||||
testing portions of your code that can be tested without relying on a multiworld to be created first.
|
||||
|
||||
#### Parametrization
|
||||
|
||||
When defining a test that needs to cover a range of inputs it is useful to parameterize (to run the same test
|
||||
for multiple inputs) the base test. Some important things to consider when attempting to parametrize your test are:
|
||||
|
||||
* [Subtests](https://docs.python.org/3/library/unittest.html#distinguishing-test-iterations-using-subtests)
|
||||
can be used to have parametrized assertions that show up similar to individual tests but without the overhead
|
||||
of needing to instantiate multiple tests; however, subtests can not be multithreaded and do not have individual
|
||||
timing data, so they are not suitable for slow tests.
|
||||
|
||||
* Archipelago's tests are test-runner-agnostic. That means tests are not allowed to use e.g. `@pytest.mark.parametrize`.
|
||||
Instead, we define our own parametrization helpers in [test.param](/test/param.py).
|
||||
|
||||
* Classes inheriting from `WorldTestBase`, including those created by the helpers in `test.param`, will run all
|
||||
base tests by default, make sure the produced tests actually do what you aim for and do not waste a lot of
|
||||
extra CPU time. Consider using `TestBase` or `unittest.TestCase` directly
|
||||
or setting `WorldTestBase.run_default_tests` to False.
|
||||
|
||||
#### Performance Considerations
|
||||
|
||||
Archipelago is big enough that the runtime of unittests can have an impact on productivity.
|
||||
|
||||
Individual tests should take less than a second, so they can be properly multithreaded.
|
||||
|
||||
Ideally, thorough tests are directed at actual code/functionality. Do not just create and/or fill a ton of individual
|
||||
Multiworlds that spend most of the test time outside what you actually want to test.
|
||||
|
||||
Consider generating/validating "random" games as part of your APWorld release workflow rather than having that be part
|
||||
of continuous integration, and add minimal reproducers to the "normal" tests for problems that were found.
|
||||
You can use [@unittest.skipIf](https://docs.python.org/3/library/unittest.html#unittest.skipIf) with an environment
|
||||
variable to keep all the benefits of the test framework while not running the marked tests by default.
|
||||
|
||||
## Running Tests
|
||||
|
||||
#### Using Pycharm
|
||||
@@ -100,3 +132,11 @@ next to the run and debug buttons.
|
||||
#### Running Tests without Pycharm
|
||||
|
||||
Run `pip install pytest pytest-subtests`, then use your IDE to run tests or run `pytest` from the source folder.
|
||||
|
||||
#### Running Tests Multithreaded
|
||||
|
||||
pytest can run multiple test runners in parallel with the pytest-xdist extension.
|
||||
|
||||
Install with `pip install pytest-xdist`.
|
||||
|
||||
Run with `pytest -n12` to spawn 12 process that each run 1/12th of the tests.
|
||||
|
||||
@@ -291,7 +291,7 @@ like entrance randomization in logic.
|
||||
|
||||
Regions have a list called `exits`, containing `Entrance` objects representing transitions to other regions.
|
||||
|
||||
There must be one special region (Called "Menu" by default, but configurable using [origin_region_name](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L295-L296)),
|
||||
There must be one special region (Called "Menu" by default, but configurable using [origin_region_name](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L298-L299)),
|
||||
from which the logic unfolds. AP assumes that a player will always be able to return to this starting region by resetting the game ("Save and quit").
|
||||
|
||||
### Entrances
|
||||
@@ -331,7 +331,7 @@ Even doing `state.can_reach_location` or `state.can_reach_entrance` is problemat
|
||||
You can use `multiworld.register_indirect_condition(region, entrance)` to explicitly tell the generator that, when a given region becomes accessible, it is necessary to re-check a specific entrance.
|
||||
You **must** use `multiworld.register_indirect_condition` if you perform this kind of `can_reach` from an entrance access rule, unless you have a **very** good technical understanding of the relevant code and can reason why it will never lead to problems in your case.
|
||||
|
||||
Alternatively, you can set [world.explicit_indirect_conditions = False](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L298-L301),
|
||||
Alternatively, you can set [world.explicit_indirect_conditions = False](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/AutoWorld.py#L301-L304),
|
||||
avoiding the need for indirect conditions at the expense of performance.
|
||||
|
||||
### Item Rules
|
||||
@@ -562,17 +562,13 @@ from .items import is_progression # this is just a dummy
|
||||
|
||||
def create_item(self, item: str) -> MyGameItem:
|
||||
# this is called when AP wants to create an item by name (for plando) or when you call it from your own code
|
||||
classification = ItemClassification.progression if is_progression(item) else
|
||||
ItemClassification.filler
|
||||
|
||||
|
||||
return MyGameItem(item, classification, self.item_name_to_id[item],
|
||||
self.player)
|
||||
classification = ItemClassification.progression if is_progression(item) else ItemClassification.filler
|
||||
return MyGameItem(item, classification, self.item_name_to_id[item], self.player)
|
||||
|
||||
|
||||
def create_event(self, event: str) -> MyGameItem:
|
||||
# while we are at it, we can also add a helper to create events
|
||||
return MyGameItem(event, True, None, self.player)
|
||||
return MyGameItem(event, ItemClassification.progression, None, self.player)
|
||||
```
|
||||
|
||||
#### create_items
|
||||
@@ -610,8 +606,8 @@ from .items import get_item_type
|
||||
|
||||
def set_rules(self) -> None:
|
||||
# For some worlds this step can be omitted if either a Logic mixin
|
||||
# (see below) is used, it's easier to apply the rules from data during
|
||||
# location generation or everything is in generate_basic
|
||||
# (see below) is used or it's easier to apply the rules from data during
|
||||
# location generation
|
||||
|
||||
# set a simple rule for an region
|
||||
set_rule(self.multiworld.get_entrance("Boss Door", self.player),
|
||||
|
||||
Reference in New Issue
Block a user