Merge branch 'ArchipelagoMW:main' into main

This commit is contained in:
CookieCat
2023-12-19 16:20:35 -05:00
committed by GitHub
10 changed files with 68 additions and 25 deletions
+10
View File
@@ -3,6 +3,16 @@
{% block head %} {% block head %}
<title>Multiworld {{ room.id|suuid }}</title> <title>Multiworld {{ room.id|suuid }}</title>
{% if should_refresh %}<meta http-equiv="refresh" content="2">{% endif %} {% if should_refresh %}<meta http-equiv="refresh" content="2">{% endif %}
<meta name="og:site_name" content="Archipelago">
<meta property="og:title" content="Multiworld {{ room.id|suuid }}">
<meta property="og:type" content="website" />
{% if room.seed.slots|length < 2 %}
<meta property="og:description" content="{{ room.seed.slots|length }} Player World
{% if room.last_port != -1 %}running on {{ config['HOST_ADDRESS'] }} with port {{ room.last_port }}{% endif %}">
{% else %}
<meta property="og:description" content="{{ room.seed.slots|length }} Players Multiworld
{% if room.last_port != -1 %}running on {{ config['HOST_ADDRESS'] }} with port {{ room.last_port }}{% endif %}">
{% endif %}
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/hostRoom.css") }}"/> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/hostRoom.css") }}"/>
{% endblock %} {% endblock %}
+30 -17
View File
@@ -2,7 +2,7 @@ import typing
from .ExtractedData import logic_options, starts, pool_options from .ExtractedData import logic_options, starts, pool_options
from .Rules import cost_terms from .Rules import cost_terms
from Options import Option, DefaultOnToggle, Toggle, Choice, Range, OptionDict, NamedRange from Options import Option, DefaultOnToggle, Toggle, Choice, Range, OptionDict, NamedRange, DeathLink
from .Charms import vanilla_costs, names as charm_names from .Charms import vanilla_costs, names as charm_names
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
@@ -402,22 +402,34 @@ class WhitePalace(Choice):
default = 0 default = 0
class DeathLink(Choice): class ExtraPlatforms(DefaultOnToggle):
"""Places additional platforms to make traveling throughout Hallownest more convenient."""
class DeathLinkShade(Choice):
"""Sets whether to create a shade when you are killed by a DeathLink and how to handle your existing shade, if any.
vanilla: DeathLink deaths function like any other death and overrides your existing shade (including geo), if any.
shadeless: DeathLink deaths do not spawn shades. Your existing shade (including geo), if any, is untouched.
shade: DeathLink deaths spawn a shade if you do not have an existing shade. Otherwise, it acts like shadeless.
* This option has no effect if DeathLink is disabled.
** Self-death shade behavior is not changed; if a self-death normally creates a shade in vanilla, it will override
your existing shade, if any.
""" """
When you die, everyone dies. Of course the reverse is true too. option_vanilla = 0
When enabled, choose how incoming deathlinks are handled:
vanilla: DeathLink kills you and is just like any other death. RIP your previous shade and geo.
shadeless: DeathLink kills you, but no shade spawns and no geo is lost. Your previous shade, if any, is untouched.
shade: DeathLink functions like a normal death if you do not already have a shade, shadeless otherwise.
"""
option_off = 0
alias_no = 0
alias_true = 1
alias_on = 1
alias_yes = 1
option_shadeless = 1 option_shadeless = 1
option_vanilla = 2 option_shade = 2
option_shade = 3 default = 2
class DeathLinkBreaksFragileCharms(Toggle):
"""Sets if fragile charms break when you are killed by a DeathLink.
* This option has no effect if DeathLink is disabled.
** Self-death fragile charm behavior is not changed; if a self-death normally breaks fragile charms in vanilla, it
will continue to do so.
"""
class StartingGeo(Range): class StartingGeo(Range):
@@ -476,7 +488,8 @@ hollow_knight_options: typing.Dict[str, type(Option)] = {
**{ **{
option.__name__: option option.__name__: option
for option in ( for option in (
StartLocation, Goal, WhitePalace, StartingGeo, DeathLink, StartLocation, Goal, WhitePalace, ExtraPlatforms, StartingGeo,
DeathLink, DeathLinkShade, DeathLinkBreaksFragileCharms,
MinimumGeoPrice, MaximumGeoPrice, MinimumGeoPrice, MaximumGeoPrice,
MinimumGrubPrice, MaximumGrubPrice, MinimumGrubPrice, MaximumGrubPrice,
MinimumEssencePrice, MaximumEssencePrice, MinimumEssencePrice, MaximumEssencePrice,
@@ -488,7 +501,7 @@ hollow_knight_options: typing.Dict[str, type(Option)] = {
LegEaterShopSlots, GrubfatherRewardSlots, LegEaterShopSlots, GrubfatherRewardSlots,
SeerRewardSlots, ExtraShopSlots, SeerRewardSlots, ExtraShopSlots,
SplitCrystalHeart, SplitMothwingCloak, SplitMantisClaw, SplitCrystalHeart, SplitMothwingCloak, SplitMantisClaw,
CostSanity, CostSanityHybridChance, CostSanity, CostSanityHybridChance
) )
}, },
**cost_sanity_weights **cost_sanity_weights
-1
View File
@@ -11,7 +11,6 @@ from .options import LingoOptions
from .player_logic import LingoPlayerLogic from .player_logic import LingoPlayerLogic
from .regions import create_regions from .regions import create_regions
from .static_logic import Room, RoomEntrance from .static_logic import Room, RoomEntrance
from .testing import LingoTestOptions
class LingoWebWorld(WebWorld): class LingoWebWorld(WebWorld):
+1 -2
View File
@@ -6,7 +6,6 @@ from .options import LocationChecks, ShuffleDoors, VictoryCondition
from .static_logic import DOORS_BY_ROOM, Door, PAINTINGS, PAINTINGS_BY_ROOM, PAINTING_ENTRANCES, PAINTING_EXITS, \ from .static_logic import DOORS_BY_ROOM, Door, PAINTINGS, PAINTINGS_BY_ROOM, PAINTING_ENTRANCES, PAINTING_EXITS, \
PANELS_BY_ROOM, PROGRESSION_BY_ROOM, REQUIRED_PAINTING_ROOMS, REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS, RoomAndDoor, \ PANELS_BY_ROOM, PROGRESSION_BY_ROOM, REQUIRED_PAINTING_ROOMS, REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS, RoomAndDoor, \
RoomAndPanel RoomAndPanel
from .testing import LingoTestOptions
if TYPE_CHECKING: if TYPE_CHECKING:
from . import LingoWorld from . import LingoWorld
@@ -224,7 +223,7 @@ class LingoPlayerLogic:
"kind of logic error.") "kind of logic error.")
if door_shuffle != ShuffleDoors.option_none and location_classification != LocationClassification.insanity \ if door_shuffle != ShuffleDoors.option_none and location_classification != LocationClassification.insanity \
and not early_color_hallways and LingoTestOptions.disable_forced_good_item is False: and not early_color_hallways is False:
# If shuffle doors is on, force a useful item onto the HI panel. This may not necessarily get you out of BK, # If shuffle doors is on, force a useful item onto the HI panel. This may not necessarily get you out of BK,
# but the goal is to allow you to reach at least one more check. The non-painting ones are hardcoded right # but the goal is to allow you to reach at least one more check. The non-painting ones are hardcoded right
# now. We only allow the entrance to the Pilgrim Room if color shuffle is off, because otherwise there are # now. We only allow the entrance to the Pilgrim Room if color shuffle is off, because otherwise there are
+10
View File
@@ -8,6 +8,8 @@ class TestRequiredRoomLogic(LingoTestBase):
} }
def test_pilgrim_first(self) -> None: def test_pilgrim_first(self) -> None:
self.remove_forced_good_item()
self.assertFalse(self.multiworld.state.can_reach("The Seeker", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("The Seeker", "Region", self.player))
self.assertFalse(self.multiworld.state.can_reach("Pilgrim Antechamber", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Pilgrim Antechamber", "Region", self.player))
self.assertFalse(self.multiworld.state.can_reach("Pilgrim Room", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Pilgrim Room", "Region", self.player))
@@ -28,6 +30,8 @@ class TestRequiredRoomLogic(LingoTestBase):
self.assertTrue(self.can_reach_location("The Seeker - Achievement")) self.assertTrue(self.can_reach_location("The Seeker - Achievement"))
def test_hidden_first(self) -> None: def test_hidden_first(self) -> None:
self.remove_forced_good_item()
self.assertFalse(self.multiworld.state.can_reach("The Seeker", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("The Seeker", "Region", self.player))
self.assertFalse(self.multiworld.state.can_reach("Pilgrim Room", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Pilgrim Room", "Region", self.player))
self.assertFalse(self.can_reach_location("The Seeker - Achievement")) self.assertFalse(self.can_reach_location("The Seeker - Achievement"))
@@ -55,6 +59,8 @@ class TestRequiredDoorLogic(LingoTestBase):
} }
def test_through_rhyme(self) -> None: def test_through_rhyme(self) -> None:
self.remove_forced_good_item()
self.assertFalse(self.can_reach_location("Rhyme Room - Circle/Looped Square Wall")) self.assertFalse(self.can_reach_location("Rhyme Room - Circle/Looped Square Wall"))
self.collect_by_name("Starting Room - Rhyme Room Entrance") self.collect_by_name("Starting Room - Rhyme Room Entrance")
@@ -64,6 +70,8 @@ class TestRequiredDoorLogic(LingoTestBase):
self.assertTrue(self.can_reach_location("Rhyme Room - Circle/Looped Square Wall")) self.assertTrue(self.can_reach_location("Rhyme Room - Circle/Looped Square Wall"))
def test_through_hidden(self) -> None: def test_through_hidden(self) -> None:
self.remove_forced_good_item()
self.assertFalse(self.can_reach_location("Rhyme Room - Circle/Looped Square Wall")) self.assertFalse(self.can_reach_location("Rhyme Room - Circle/Looped Square Wall"))
self.collect_by_name("Starting Room - Rhyme Room Entrance") self.collect_by_name("Starting Room - Rhyme Room Entrance")
@@ -83,6 +91,8 @@ class TestSimpleDoors(LingoTestBase):
} }
def test_requirement(self): def test_requirement(self):
self.remove_forced_good_item()
self.assertFalse(self.multiworld.state.can_reach("Outside The Wanderer", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Outside The Wanderer", "Region", self.player))
self.assertFalse(self.multiworld.state.can_reach("Orange Tower Third Floor", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Orange Tower Third Floor", "Region", self.player))
+4
View File
@@ -8,6 +8,8 @@ class TestProgressiveOrangeTower(LingoTestBase):
} }
def test_from_welcome_back(self) -> None: def test_from_welcome_back(self) -> None:
self.remove_forced_good_item()
self.assertFalse(self.multiworld.state.can_reach("Orange Tower First Floor", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Orange Tower First Floor", "Region", self.player))
self.assertFalse(self.multiworld.state.can_reach("Orange Tower Second Floor", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Orange Tower Second Floor", "Region", self.player))
self.assertFalse(self.multiworld.state.can_reach("Orange Tower Third Floor", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Orange Tower Third Floor", "Region", self.player))
@@ -83,6 +85,8 @@ class TestProgressiveOrangeTower(LingoTestBase):
self.assertTrue(self.multiworld.state.can_reach("Orange Tower Seventh Floor", "Region", self.player)) self.assertTrue(self.multiworld.state.can_reach("Orange Tower Seventh Floor", "Region", self.player))
def test_from_hub_room(self) -> None: def test_from_hub_room(self) -> None:
self.remove_forced_good_item()
self.assertFalse(self.multiworld.state.can_reach("Orange Tower First Floor", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Orange Tower First Floor", "Region", self.player))
self.assertFalse(self.multiworld.state.can_reach("Orange Tower Second Floor", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Orange Tower Second Floor", "Region", self.player))
self.assertFalse(self.multiworld.state.can_reach("Orange Tower Third Floor", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Orange Tower Third Floor", "Region", self.player))
+6
View File
@@ -7,6 +7,8 @@ class TestComplexProgressiveHallwayRoom(LingoTestBase):
} }
def test_item(self): def test_item(self):
self.remove_forced_good_item()
self.assertFalse(self.multiworld.state.can_reach("Outside The Agreeable", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Outside The Agreeable", "Region", self.player))
self.assertFalse(self.multiworld.state.can_reach("Hallway Room (2)", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Hallway Room (2)", "Region", self.player))
self.assertFalse(self.multiworld.state.can_reach("Hallway Room (3)", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Hallway Room (3)", "Region", self.player))
@@ -58,6 +60,8 @@ class TestSimpleHallwayRoom(LingoTestBase):
} }
def test_item(self): def test_item(self):
self.remove_forced_good_item()
self.assertFalse(self.multiworld.state.can_reach("Outside The Agreeable", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Outside The Agreeable", "Region", self.player))
self.assertFalse(self.multiworld.state.can_reach("Hallway Room (2)", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Hallway Room (2)", "Region", self.player))
self.assertFalse(self.multiworld.state.can_reach("Hallway Room (3)", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Hallway Room (3)", "Region", self.player))
@@ -86,6 +90,8 @@ class TestProgressiveArtGallery(LingoTestBase):
} }
def test_item(self): def test_item(self):
self.remove_forced_good_item()
self.assertFalse(self.multiworld.state.can_reach("Art Gallery", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Art Gallery", "Region", self.player))
self.assertFalse(self.multiworld.state.can_reach("Art Gallery (Second Floor)", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Art Gallery (Second Floor)", "Region", self.player))
self.assertFalse(self.multiworld.state.can_reach("Art Gallery (Third Floor)", "Region", self.player)) self.assertFalse(self.multiworld.state.can_reach("Art Gallery (Third Floor)", "Region", self.player))
+6 -2
View File
@@ -1,7 +1,6 @@
from typing import ClassVar from typing import ClassVar
from test.bases import WorldTestBase from test.bases import WorldTestBase
from .. import LingoTestOptions
class LingoTestBase(WorldTestBase): class LingoTestBase(WorldTestBase):
@@ -9,5 +8,10 @@ class LingoTestBase(WorldTestBase):
player: ClassVar[int] = 1 player: ClassVar[int] = 1
def world_setup(self, *args, **kwargs): def world_setup(self, *args, **kwargs):
LingoTestOptions.disable_forced_good_item = True
super().world_setup(*args, **kwargs) super().world_setup(*args, **kwargs)
def remove_forced_good_item(self):
location = self.multiworld.get_location("Second Room - Good Luck", self.player)
self.remove(location.item)
self.multiworld.itempool.append(location.item)
self.multiworld.state.events.add(location)
-2
View File
@@ -1,2 +0,0 @@
class LingoTestOptions:
disable_forced_good_item: bool = False
+1 -1
View File
@@ -414,7 +414,7 @@ class PokemonRedBlueWorld(World):
> 7) or (self.multiworld.door_shuffle[self.player] not in ("off", "simple")))): > 7) or (self.multiworld.door_shuffle[self.player] not in ("off", "simple")))):
intervene_move = "Cut" intervene_move = "Cut"
elif ((not logic.can_learn_hm(test_state, "Flash", self.player)) and self.multiworld.dark_rock_tunnel_logic[self.player] elif ((not logic.can_learn_hm(test_state, "Flash", self.player)) and self.multiworld.dark_rock_tunnel_logic[self.player]
and (((self.multiworld.accessibility[self.player] != "minimal" and and (((self.multiworld.accessibility[self.player] != "minimal" or
(self.multiworld.trainersanity[self.player] or self.multiworld.extra_key_items[self.player])) or (self.multiworld.trainersanity[self.player] or self.multiworld.extra_key_items[self.player])) or
self.multiworld.door_shuffle[self.player]))): self.multiworld.door_shuffle[self.player]))):
intervene_move = "Flash" intervene_move = "Flash"