mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-07-05 10:09:34 -07:00
Merge branch 'ArchipelagoMW:main' into main
This commit is contained in:
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
class LingoTestOptions:
|
|
||||||
disable_forced_good_item: bool = False
|
|
||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user