mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-05-27 15:50:02 -07:00
Merge branch 'main' into tunc-logic-rules-redux
This commit is contained in:
+17
-2
@@ -123,8 +123,8 @@ class WebWorldRegister(type):
|
||||
assert group.options, "A custom defined Option Group must contain at least one Option."
|
||||
# catch incorrectly titled versions of the prebuilt groups so they don't create extra groups
|
||||
title_name = group.name.title()
|
||||
if title_name in prebuilt_options:
|
||||
group.name = title_name
|
||||
assert title_name not in prebuilt_options or title_name == group.name, \
|
||||
f"Prebuilt group name \"{group.name}\" must be \"{title_name}\""
|
||||
|
||||
if group.name == "Item & Location Options":
|
||||
assert not any(option in item_and_loc_options for option in group.options), \
|
||||
@@ -223,6 +223,21 @@ class WebWorld(metaclass=WebWorldRegister):
|
||||
option_groups: ClassVar[List[OptionGroup]] = []
|
||||
"""Ordered list of option groupings. Any options not set in a group will be placed in a pre-built "Game Options"."""
|
||||
|
||||
rich_text_options_doc = False
|
||||
"""Whether the WebHost should render Options' docstrings as rich text.
|
||||
|
||||
If this is True, Options' docstrings are interpreted as reStructuredText_,
|
||||
the standard Python markup format. In the WebHost, they're rendered to HTML
|
||||
so that lists, emphasis, and other rich text features are displayed
|
||||
properly.
|
||||
|
||||
If this is False, the docstrings are instead interpreted as plain text, and
|
||||
displayed as-is on the WebHost with whitespace preserved. For backwards
|
||||
compatibility, this is the default.
|
||||
|
||||
.. _reStructuredText: https://docutils.sourceforge.io/rst.html
|
||||
"""
|
||||
|
||||
location_descriptions: Dict[str, str] = {}
|
||||
"""An optional map from location names (or location group names) to brief descriptions for users."""
|
||||
|
||||
|
||||
@@ -128,3 +128,4 @@ from .AutoWorld import AutoWorldRegister
|
||||
network_data_package: DataPackage = {
|
||||
"games": {world_name: world.get_data_package_data() for world_name, world in AutoWorldRegister.world_types.items()},
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,11 @@ class kill_switch:
|
||||
logger.debug("kill_switch: Add switch")
|
||||
cls._to_kill.append(value)
|
||||
|
||||
@classmethod
|
||||
def kill(cls, value):
|
||||
logger.info(f"kill_switch: Process cleanup for 1 process")
|
||||
value._clean(verbose=False)
|
||||
|
||||
@classmethod
|
||||
def kill_all(cls):
|
||||
logger.info(f"kill_switch: Process cleanup for {len(cls._to_kill)} processes")
|
||||
@@ -116,7 +121,7 @@ class SC2Process:
|
||||
async def __aexit__(self, *args):
|
||||
logger.exception("async exit")
|
||||
await self._close_connection()
|
||||
kill_switch.kill_all()
|
||||
kill_switch.kill(self)
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
|
||||
@property
|
||||
|
||||
@@ -220,26 +220,7 @@ def get_invalid_bunny_revival_dungeons():
|
||||
yield 'Sanctuary'
|
||||
|
||||
|
||||
def no_logic_rules(world, player):
|
||||
"""
|
||||
Add OWG transitions to no logic player's world
|
||||
"""
|
||||
create_no_logic_connections(player, world, get_boots_clip_exits_lw(world.mode[player] == 'inverted'))
|
||||
create_no_logic_connections(player, world, get_boots_clip_exits_dw(world.mode[player] == 'inverted', player))
|
||||
|
||||
# Glitched speed drops.
|
||||
create_no_logic_connections(player, world, get_glitched_speed_drops_dw(world.mode[player] == 'inverted'))
|
||||
|
||||
# Mirror clip spots.
|
||||
if world.mode[player] != 'inverted':
|
||||
create_no_logic_connections(player, world, get_mirror_clip_spots_dw())
|
||||
create_no_logic_connections(player, world, get_mirror_offset_spots_dw())
|
||||
else:
|
||||
create_no_logic_connections(player, world, get_mirror_offset_spots_lw(player))
|
||||
|
||||
|
||||
def overworld_glitch_connections(world, player):
|
||||
|
||||
# Boots-accessible locations.
|
||||
create_owg_connections(player, world, get_boots_clip_exits_lw(world.mode[player] == 'inverted'))
|
||||
create_owg_connections(player, world, get_boots_clip_exits_dw(world.mode[player] == 'inverted', player))
|
||||
|
||||
@@ -10,7 +10,7 @@ from . import OverworldGlitchRules
|
||||
from .Bosses import GanonDefeatRule
|
||||
from .Items import item_factory, item_name_groups, item_table, progression_items
|
||||
from .Options import small_key_shuffle
|
||||
from .OverworldGlitchRules import no_logic_rules, overworld_glitches_rules
|
||||
from .OverworldGlitchRules import overworld_glitches_rules
|
||||
from .Regions import LTTPRegionType, location_table
|
||||
from .StateHelpers import (can_extend_magic, can_kill_most_things,
|
||||
can_lift_heavy_rocks, can_lift_rocks,
|
||||
@@ -33,7 +33,6 @@ def set_rules(world):
|
||||
'WARNING! Seeds generated under this logic often require major glitches and may be impossible!')
|
||||
|
||||
if world.players == 1:
|
||||
no_logic_rules(world, player)
|
||||
for exit in world.get_region('Menu', player).exits:
|
||||
exit.hide_path = True
|
||||
return
|
||||
|
||||
@@ -16,6 +16,7 @@ from .regions import create_regions
|
||||
|
||||
class LingoWebWorld(WebWorld):
|
||||
option_groups = lingo_option_groups
|
||||
rich_text_options_doc = True
|
||||
theme = "grass"
|
||||
tutorials = [Tutorial(
|
||||
"Multiworld Setup Guide",
|
||||
|
||||
+81
-39
@@ -9,8 +9,12 @@ from .items import TRAP_ITEMS
|
||||
|
||||
class ShuffleDoors(Choice):
|
||||
"""If on, opening doors will require their respective "keys".
|
||||
In "simple", doors are sorted into logical groups, which are all opened by receiving an item.
|
||||
In "complex", the items are much more granular, and will usually only open a single door each."""
|
||||
|
||||
- **Simple:** Doors are sorted into logical groups, which are all opened by
|
||||
receiving an item.
|
||||
- **Complex:** The items are much more granular, and will usually only open
|
||||
a single door each.
|
||||
"""
|
||||
display_name = "Shuffle Doors"
|
||||
option_none = 0
|
||||
option_simple = 1
|
||||
@@ -19,24 +23,37 @@ class ShuffleDoors(Choice):
|
||||
|
||||
class ProgressiveOrangeTower(DefaultOnToggle):
|
||||
"""When "Shuffle Doors" is on, this setting governs the manner in which the Orange Tower floors open up.
|
||||
If off, there is an item for each floor of the tower, and each floor's item is the only one needed to access that floor.
|
||||
If on, there are six progressive items, which open up the tower from the bottom floor upward.
|
||||
|
||||
- **Off:** There is an item for each floor of the tower, and each floor's
|
||||
item is the only one needed to access that floor.
|
||||
- **On:** There are six progressive items, which open up the tower from the
|
||||
bottom floor upward.
|
||||
"""
|
||||
display_name = "Progressive Orange Tower"
|
||||
|
||||
|
||||
class ProgressiveColorful(DefaultOnToggle):
|
||||
"""When "Shuffle Doors" is on "complex", this setting governs the manner in which The Colorful opens up.
|
||||
If off, there is an item for each room of The Colorful, meaning that random rooms in the middle of the sequence can open up without giving you access to them.
|
||||
If on, there are ten progressive items, which open up the sequence from White forward."""
|
||||
|
||||
- **Off:** There is an item for each room of The Colorful, meaning that
|
||||
random rooms in the middle of the sequence can open up without giving you
|
||||
access to them.
|
||||
- **On:** There are ten progressive items, which open up the sequence from
|
||||
White forward.
|
||||
"""
|
||||
display_name = "Progressive Colorful"
|
||||
|
||||
|
||||
class LocationChecks(Choice):
|
||||
"""Determines what locations are available.
|
||||
On "normal", there will be a location check for each panel set that would ordinarily open a door, as well as for achievement panels and a small handful of other panels.
|
||||
On "reduced", many of the locations that are associated with opening doors are removed.
|
||||
On "insanity", every individual panel in the game is a location check."""
|
||||
|
||||
- **Normal:** There will be a location check for each panel set that would
|
||||
ordinarily open a door, as well as for achievement panels and a small
|
||||
handful of other panels.
|
||||
- **Reduced:** Many of the locations that are associated with opening doors
|
||||
are removed.
|
||||
- **Insanity:** Every individual panel in the game is a location check.
|
||||
"""
|
||||
display_name = "Location Checks"
|
||||
option_normal = 0
|
||||
option_reduced = 1
|
||||
@@ -44,16 +61,20 @@ class LocationChecks(Choice):
|
||||
|
||||
|
||||
class ShuffleColors(DefaultOnToggle):
|
||||
"""
|
||||
If on, an item is added to the pool for every puzzle color (besides White).
|
||||
You will need to unlock the requisite colors in order to be able to solve puzzles of that color.
|
||||
"""If on, an item is added to the pool for every puzzle color (besides White).
|
||||
|
||||
You will need to unlock the requisite colors in order to be able to solve
|
||||
puzzles of that color.
|
||||
"""
|
||||
display_name = "Shuffle Colors"
|
||||
|
||||
|
||||
class ShufflePanels(Choice):
|
||||
"""If on, the puzzles on each panel are randomized.
|
||||
On "rearrange", the puzzles are the same as the ones in the base game, but are placed in different areas."""
|
||||
|
||||
On "rearrange", the puzzles are the same as the ones in the base game, but
|
||||
are placed in different areas.
|
||||
"""
|
||||
display_name = "Shuffle Panels"
|
||||
option_none = 0
|
||||
option_rearrange = 1
|
||||
@@ -66,22 +87,26 @@ class ShufflePaintings(Toggle):
|
||||
|
||||
class EnablePilgrimage(Toggle):
|
||||
"""Determines how the pilgrimage works.
|
||||
If on, you are required to complete a pilgrimage in order to access the Pilgrim Antechamber.
|
||||
If off, the pilgrimage will be deactivated, and the sun painting will be added to the pool, even if door shuffle is off."""
|
||||
|
||||
- **On:** You are required to complete a pilgrimage in order to access the
|
||||
Pilgrim Antechamber.
|
||||
- **Off:** The pilgrimage will be deactivated, and the sun painting will be
|
||||
added to the pool, even if door shuffle is off.
|
||||
"""
|
||||
display_name = "Enable Pilgrimage"
|
||||
|
||||
|
||||
class PilgrimageAllowsRoofAccess(DefaultOnToggle):
|
||||
"""
|
||||
If on, you may use the Crossroads roof access during a pilgrimage (and you may be expected to do so).
|
||||
"""If on, you may use the Crossroads roof access during a pilgrimage (and you may be expected to do so).
|
||||
|
||||
Otherwise, pilgrimage will be deactivated when going up the stairs.
|
||||
"""
|
||||
display_name = "Allow Roof Access for Pilgrimage"
|
||||
|
||||
|
||||
class PilgrimageAllowsPaintings(DefaultOnToggle):
|
||||
"""
|
||||
If on, you may use paintings during a pilgrimage (and you may be expected to do so).
|
||||
"""If on, you may use paintings during a pilgrimage (and you may be expected to do so).
|
||||
|
||||
Otherwise, pilgrimage will be deactivated when going through a painting.
|
||||
"""
|
||||
display_name = "Allow Paintings for Pilgrimage"
|
||||
@@ -89,11 +114,17 @@ class PilgrimageAllowsPaintings(DefaultOnToggle):
|
||||
|
||||
class SunwarpAccess(Choice):
|
||||
"""Determines how access to sunwarps works.
|
||||
On "normal", all sunwarps are enabled from the start.
|
||||
On "disabled", all sunwarps are disabled. Pilgrimage must be disabled when this is used.
|
||||
On "unlock", sunwarps start off disabled, and all six activate once you receive an item.
|
||||
On "individual", sunwarps start off disabled, and each has a corresponding item that unlocks it.
|
||||
On "progressive", sunwarps start off disabled, and they unlock in order using a progressive item."""
|
||||
|
||||
- **Normal:** All sunwarps are enabled from the start.
|
||||
- **Disabled:** All sunwarps are disabled. Pilgrimage must be disabled when
|
||||
this is used.
|
||||
- **Unlock:** Sunwarps start off disabled, and all six activate once you
|
||||
receive an item.
|
||||
- **Individual:** Sunwarps start off disabled, and each has a corresponding
|
||||
item that unlocks it.
|
||||
- **Progressive:** Sunwarps start off disabled, and they unlock in order
|
||||
using a progressive item.
|
||||
"""
|
||||
display_name = "Sunwarp Access"
|
||||
option_normal = 0
|
||||
option_disabled = 1
|
||||
@@ -109,10 +140,16 @@ class ShuffleSunwarps(Toggle):
|
||||
|
||||
class VictoryCondition(Choice):
|
||||
"""Change the victory condition.
|
||||
On "the_end", the goal is to solve THE END at the top of the tower.
|
||||
On "the_master", the goal is to solve THE MASTER at the top of the tower, after getting the number of achievements specified in the Mastery Achievements option.
|
||||
On "level_2", the goal is to solve LEVEL 2 in the second room, after solving the number of panels specified in the Level 2 Requirement option.
|
||||
On "pilgrimage", the goal is to solve PILGRIM in the Pilgrim Antechamber, typically after performing a Pilgrimage."""
|
||||
|
||||
- **The End:** the goal is to solve THE END at the top of the tower.
|
||||
- **The Master:** The goal is to solve THE MASTER at the top of the tower,
|
||||
after getting the number of achievements specified in the Mastery
|
||||
Achievements option.
|
||||
- **Level 2:** The goal is to solve LEVEL 2 in the second room, after
|
||||
solving the number of panels specified in the Level 2 Requirement option.
|
||||
- **Pilgrimage:** The goal is to solve PILGRIM in the Pilgrim Antechamber,
|
||||
typically after performing a Pilgrimage.
|
||||
"""
|
||||
display_name = "Victory Condition"
|
||||
option_the_end = 0
|
||||
option_the_master = 1
|
||||
@@ -122,9 +159,12 @@ class VictoryCondition(Choice):
|
||||
|
||||
class MasteryAchievements(Range):
|
||||
"""The number of achievements required to unlock THE MASTER.
|
||||
In the base game, 21 achievements are needed.
|
||||
If you include The Scientific and The Unchallenged, which are in the base game but are not counted for mastery, 23 would be required.
|
||||
If you include the custom achievement (The Wanderer), 24 would be required.
|
||||
|
||||
- In the base game, 21 achievements are needed.
|
||||
- If you include The Scientific and The Unchallenged, which are in the base
|
||||
game but are not counted for mastery, 23 would be required.
|
||||
- If you include the custom achievement (The Wanderer), 24 would be
|
||||
required.
|
||||
"""
|
||||
display_name = "Mastery Achievements"
|
||||
range_start = 1
|
||||
@@ -134,9 +174,10 @@ class MasteryAchievements(Range):
|
||||
|
||||
class Level2Requirement(Range):
|
||||
"""The number of panel solves required to unlock LEVEL 2.
|
||||
In the base game, 223 are needed.
|
||||
Note that this count includes ANOTHER TRY.
|
||||
When set to 1, the panel hunt is disabled, and you can access LEVEL 2 for free.
|
||||
|
||||
In the base game, 223 are needed. Note that this count includes ANOTHER TRY.
|
||||
When set to 1, the panel hunt is disabled, and you can access LEVEL 2 for
|
||||
free.
|
||||
"""
|
||||
display_name = "Level 2 Requirement"
|
||||
range_start = 1
|
||||
@@ -145,9 +186,10 @@ class Level2Requirement(Range):
|
||||
|
||||
|
||||
class EarlyColorHallways(Toggle):
|
||||
"""
|
||||
When on, a painting warp to the color hallways area will appear in the starting room.
|
||||
This lets you avoid being trapped in the starting room for long periods of time when door shuffle is on.
|
||||
"""When on, a painting warp to the color hallways area will appear in the starting room.
|
||||
|
||||
This lets you avoid being trapped in the starting room for long periods of
|
||||
time when door shuffle is on.
|
||||
"""
|
||||
display_name = "Early Color Hallways"
|
||||
|
||||
@@ -161,8 +203,8 @@ class TrapPercentage(Range):
|
||||
|
||||
|
||||
class TrapWeights(OptionDict):
|
||||
"""
|
||||
Specify the distribution of traps that should be placed into the pool.
|
||||
"""Specify the distribution of traps that should be placed into the pool.
|
||||
|
||||
If you don't want a specific type of trap, set the weight to zero.
|
||||
"""
|
||||
display_name = "Trap Weights"
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Pokemon Emerald
|
||||
|
||||
Version 2.0.0
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
7. Install protontricks, on the Steam Deck this can be done via the Discover store, on other distros instructions vary, [see its github page](https://github.com/Matoking/protontricks).
|
||||
|
||||
8. Download the [.NET 7 Desktop Runtime for x64 Windows](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-7.0.17-windows-x64-installer}. If this link does not work, the download can be found on [this page](https://dotnet.microsoft.com/en-us/download/dotnet/7.0).
|
||||
8. Download the [.NET 7 Desktop Runtime for x64 Windows](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-7.0.17-windows-x64-installer). If this link does not work, the download can be found on [this page](https://dotnet.microsoft.com/en-us/download/dotnet/7.0).
|
||||
|
||||
9. Right click the .NET 7 Desktop Runtime exe, and assuming protontricks was installed correctly, the option to "Open with Protontricks Launcher" should be available. Click that, and in the popup window that opens, select SAModManager.exe. Follow the prompts after this to install the .NET 7 Desktop Runtime for SAModManager. Once it is done, you should be able to successfully launch SAModManager to steam.
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ def create_regions_and_locations(world: MultiWorld, player: int, precalculated_w
|
||||
logic = TimespinnerLogic(world, player, precalculated_weights)
|
||||
|
||||
connect(world, player, 'Lake desolation', 'Lower lake desolation', lambda state: flooded.flood_lake_desolation or logic.has_timestop(state) or state.has('Talaria Attachment', player))
|
||||
connect(world, player, 'Lake desolation', 'Upper lake desolation', lambda state: logic.has_fire(state) and state.can_reach('Upper Lake Serene', 'Region', player))
|
||||
connect(world, player, 'Lake desolation', 'Upper lake desolation', lambda state: logic.has_fire(state) and state.can_reach('Upper Lake Serene', 'Region', player), "Upper Lake Serene")
|
||||
connect(world, player, 'Lake desolation', 'Skeleton Shaft', lambda state: flooded.flood_lake_desolation or logic.has_doublejump(state))
|
||||
connect(world, player, 'Lake desolation', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Upper lake desolation', 'Lake desolation')
|
||||
@@ -80,7 +80,7 @@ def create_regions_and_locations(world: MultiWorld, player: int, precalculated_w
|
||||
connect(world, player, 'Eastern lake desolation', 'Space time continuum', logic.has_teleport)
|
||||
connect(world, player, 'Eastern lake desolation', 'Library')
|
||||
connect(world, player, 'Eastern lake desolation', 'Lower lake desolation')
|
||||
connect(world, player, 'Eastern lake desolation', 'Upper lake desolation', lambda state: logic.has_fire(state) and state.can_reach('Upper Lake Serene', 'Region', player))
|
||||
connect(world, player, 'Eastern lake desolation', 'Upper lake desolation', lambda state: logic.has_fire(state) and state.can_reach('Upper Lake Serene', 'Region', player), "Upper Lake Serene")
|
||||
connect(world, player, 'Library', 'Eastern lake desolation')
|
||||
connect(world, player, 'Library', 'Library top', lambda state: logic.has_doublejump(state) or state.has('Talaria Attachment', player))
|
||||
connect(world, player, 'Library', 'Varndagroth tower left', logic.has_keycard_D)
|
||||
@@ -185,7 +185,7 @@ def create_regions_and_locations(world: MultiWorld, player: int, precalculated_w
|
||||
if is_option_enabled(world, player, "GyreArchives"):
|
||||
connect(world, player, 'The lab (upper)', 'Ravenlord\'s Lair', lambda state: state.has('Merchant Crow', player))
|
||||
connect(world, player, 'Ravenlord\'s Lair', 'The lab (upper)')
|
||||
connect(world, player, 'Library top', 'Ifrit\'s Lair', lambda state: state.has('Kobo', player) and state.can_reach('Refugee Camp', 'Region', player))
|
||||
connect(world, player, 'Library top', 'Ifrit\'s Lair', lambda state: state.has('Kobo', player) and state.can_reach('Refugee Camp', 'Region', player), "Refugee Camp")
|
||||
connect(world, player, 'Ifrit\'s Lair', 'Library top')
|
||||
|
||||
|
||||
@@ -242,11 +242,19 @@ def connectStartingRegion(world: MultiWorld, player: int):
|
||||
|
||||
|
||||
def connect(world: MultiWorld, player: int, source: str, target: str,
|
||||
rule: Optional[Callable[[CollectionState], bool]] = None):
|
||||
rule: Optional[Callable[[CollectionState], bool]] = None,
|
||||
indirect: str = ""):
|
||||
|
||||
sourceRegion = world.get_region(source, player)
|
||||
targetRegion = world.get_region(target, player)
|
||||
sourceRegion.connect(targetRegion, rule=rule)
|
||||
entrance = sourceRegion.connect(targetRegion, rule=rule)
|
||||
|
||||
if indirect:
|
||||
indirectRegion = world.get_region(indirect, player)
|
||||
if indirectRegion in world.indirect_connections:
|
||||
world.indirect_connections[indirectRegion].add(entrance)
|
||||
else:
|
||||
world.indirect_connections[indirectRegion] = {entrance}
|
||||
|
||||
|
||||
def split_location_datas_per_region(locations: List[LocationData]) -> Dict[str, List[LocationData]]:
|
||||
|
||||
Reference in New Issue
Block a user