The Messenger: some miscellaneous cleanup. Also found a logic bug. oops. (#1654)

This commit is contained in:
alwaysintreble 2023-04-03 19:27:36 -05:00 committed by GitHub
parent ffd968d89d
commit cdd460ae15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 37 additions and 33 deletions

View File

@ -6,7 +6,7 @@ NOTES = [
"Key of Courage", "Key of Courage",
"Key of Love", "Key of Love",
"Key of Strength", "Key of Strength",
"Key of Symbiosis" "Key of Symbiosis",
] ]
PROG_ITEMS = [ PROG_ITEMS = [
@ -20,18 +20,18 @@ PROG_ITEMS = [
"Sun Crest", "Sun Crest",
"Moon Crest", "Moon Crest",
# "Astral Seed", # "Astral Seed",
# "Astral Tea Leaves" # "Astral Tea Leaves",
] ]
PHOBEKINS = [ PHOBEKINS = [
"Necro", "Necro",
"Pyro", "Pyro",
"Claustro", "Claustro",
"Acro" "Acro",
] ]
USEFUL_ITEMS = [ USEFUL_ITEMS = [
"Windmill Shuriken" "Windmill Shuriken",
] ]
# item_name_to_id needs to be deterministic and match upstream # item_name_to_id needs to be deterministic and match upstream
@ -53,7 +53,7 @@ ALL_ITEMS = [
"Moon Crest", "Moon Crest",
*PHOBEKINS, *PHOBEKINS,
"Power Seal", "Power Seal",
"Time Shard" # there's 45 separate instances of this in the client lookup, but hopefully we don't care? "Time Shard", # there's 45 separate instances of this in the client lookup, but hopefully we don't care?
] ]
# locations # locations
@ -87,7 +87,7 @@ ALWAYS_LOCATIONS = [
"Necro", "Necro",
"Pyro", "Pyro",
"Claustro", "Claustro",
"Acro" "Acro",
] ]
SEALS = [ SEALS = [
@ -149,5 +149,5 @@ SEALS = [
"Elemental Skylands Seal - Air", "Elemental Skylands Seal - Air",
"Elemental Skylands Seal - Water", "Elemental Skylands Seal - Water",
"Elemental Skylands Seal - Fire" "Elemental Skylands Seal - Fire",
] ]

View File

@ -22,7 +22,7 @@ REGIONS: Dict[str, List[str]] = {
"Sunken Shrine": ["Ninja Tabi", "Sun Crest", "Moon Crest", "Key of Love"], "Sunken Shrine": ["Ninja Tabi", "Sun Crest", "Moon Crest", "Key of Love"],
"Elemental Skylands": ["Key of Symbiosis"], "Elemental Skylands": ["Key of Symbiosis"],
"Corrupted Future": ["Key of Courage"], "Corrupted Future": ["Key of Courage"],
"Music Box": ["Rescue Phantom"] "Music Box": ["Rescue Phantom"],
} }
"""seal locations have the region in their name and may not need to be created so skip them here""" """seal locations have the region in their name and may not need to be created so skip them here"""
@ -47,6 +47,6 @@ REGION_CONNECTIONS: Dict[str, Set[str]] = {
"Dark Cave": {"Catacombs", "Riviere Turquoise"}, "Dark Cave": {"Catacombs", "Riviere Turquoise"},
"Riviere Turquoise": set(), "Riviere Turquoise": set(),
"Sunken Shrine": {"Howling Grotto"}, "Sunken Shrine": {"Howling Grotto"},
"Elemental Skylands": set() "Elemental Skylands": set(),
} }
"""Vanilla layout mapping with all Tower HQ portals open. from -> to""" """Vanilla layout mapping with all Tower HQ portals open. from -> to"""

View File

@ -32,7 +32,7 @@ class MessengerRules:
"Forlorn Temple": lambda state: state.has_all({"Wingsuit", *PHOBEKINS}, self.player), "Forlorn Temple": lambda state: state.has_all({"Wingsuit", *PHOBEKINS}, self.player),
"Glacial Peak": self.has_vertical, "Glacial Peak": self.has_vertical,
"Elemental Skylands": lambda state: state.has("Fairy Bottle", self.player), "Elemental Skylands": lambda state: state.has("Fairy Bottle", self.player),
"Music Box": lambda state: state.has_all(set(NOTES), self.player) and self.has_vertical(state) "Music Box": lambda state: state.has_all(set(NOTES), self.player) and self.has_vertical(state),
} }
self.location_rules = { self.location_rules = {
@ -44,6 +44,7 @@ class MessengerRules:
"Howling Grotto Seal - Windy Saws and Balls": self.has_wingsuit, "Howling Grotto Seal - Windy Saws and Balls": self.has_wingsuit,
"Howling Grotto Seal - Crushing Pits": lambda state: self.has_wingsuit(state) and self.has_dart(state), "Howling Grotto Seal - Crushing Pits": lambda state: self.has_wingsuit(state) and self.has_dart(state),
# searing crags # searing crags
"Astral Tea Leaves": lambda state: state.can_reach("Astral Seed", "Location", self.player),
"Key of Strength": lambda state: state.has("Power Thistle", self.player), "Key of Strength": lambda state: state.has("Power Thistle", self.player),
# glacial peak # glacial peak
"Glacial Peak Seal - Ice Climbers": self.has_dart, "Glacial Peak Seal - Ice Climbers": self.has_dart,
@ -74,7 +75,7 @@ class MessengerRules:
# corrupted future # corrupted future
"Key of Courage": lambda state: state.has_all({"Demon King Crown", "Fairy Bottle"}, self.player), "Key of Courage": lambda state: state.has_all({"Demon King Crown", "Fairy Bottle"}, self.player),
# the shop # the shop
"Shop Chest": self.has_enough_seals "Shop Chest": self.has_enough_seals,
} }
def has_wingsuit(self, state: CollectionState) -> bool: def has_wingsuit(self, state: CollectionState) -> bool:
@ -165,7 +166,7 @@ class MessengerChallengeRules(MessengerHardRules):
self.region_rules.update({ self.region_rules.update({
"Forlorn Temple": lambda state: (self.has_vertical(state) and state.has_all(set(PHOBEKINS), self.player)) "Forlorn Temple": lambda state: (self.has_vertical(state) and state.has_all(set(PHOBEKINS), self.player))
or state.has_all({"Wingsuit", "Windmill Shuriken"}, self.player), or state.has_all({"Wingsuit", "Windmill Shuriken"}, self.player),
"Elemental Skylands": lambda state: self.has_wingsuit(state) or state.has("Fairy Bottle", self.player) "Elemental Skylands": lambda state: self.has_wingsuit(state) or state.has("Fairy Bottle", self.player),
}) })
self.location_rules.update({ self.location_rules.update({
@ -188,7 +189,7 @@ class MessengerOOBRules(MessengerRules):
self.region_rules = { self.region_rules = {
"Elemental Skylands": lambda state: state.has_any({"Wingsuit", "Rope Dart", "Fairy Bottle"}, self.player), "Elemental Skylands": lambda state: state.has_any({"Wingsuit", "Rope Dart", "Fairy Bottle"}, self.player),
"Music Box": lambda state: state.has_all(set(NOTES), self.player) "Music Box": lambda state: state.has_all(set(NOTES), self.player),
} }
self.location_rules = { self.location_rules = {
@ -203,7 +204,7 @@ class MessengerOOBRules(MessengerRules):
"Underworld Seal - Fireball Wave": lambda state: state.has_any({"Wingsuit", "Windmill Shuriken"}, "Underworld Seal - Fireball Wave": lambda state: state.has_any({"Wingsuit", "Windmill Shuriken"},
self.player), self.player),
"Tower of Time Seal - Time Waster Seal": self.has_dart, "Tower of Time Seal - Time Waster Seal": self.has_dart,
"Shop Chest": self.has_enough_seals "Shop Chest": self.has_enough_seals,
} }
def set_messenger_rules(self) -> None: def set_messenger_rules(self) -> None:

View File

@ -20,7 +20,7 @@ class MessengerWeb(WebWorld):
"English", "English",
"setup_en.md", "setup_en.md",
"setup/en", "setup/en",
["alwaysintreble"] ["alwaysintreble"],
) )
tutorials = [tut_en] tutorials = [tut_en]
@ -89,7 +89,7 @@ class MessengerWorld(World):
if item not in if item not in
{ {
"Power Seal", "Time Shard", *NOTES, "Power Seal", "Time Shard", *NOTES,
*{collected_item.name for collected_item in self.multiworld.precollected_items[self.player]} *{collected_item.name for collected_item in self.multiworld.precollected_items[self.player]},
# this is a set and currently won't create items for anything that appears in here at all # this is a set and currently won't create items for anything that appears in here at all
# if we get in a position where this can have duplicates of items that aren't Power Seals # if we get in a position where this can have duplicates of items that aren't Power Seals
# or Time shards, this will need to be redone. # or Time shards, this will need to be redone.

View File

@ -56,20 +56,22 @@ for it. The groups you can use for The Messenger are:
is recommended to quit to title and reload the save is recommended to quit to title and reload the save
* After reaching ninja village a teleport option is added to the menu to reach it quickly * After reaching ninja village a teleport option is added to the menu to reach it quickly
* Toggle Windmill Shuriken button is added to option menu once the item is received * Toggle Windmill Shuriken button is added to option menu once the item is received
* The mod option menu will also have a hint item button, as well as a release and collect button that are all placed when
the player fulfills the necessary conditions.
## Currently known issues ## Currently known issues
* Necro cutscene will sometimes not play correctly, but will still reward the item * Necro cutscene will sometimes not play correctly, but will still reward the item
* Ruxxtin Coffin cutscene will sometimes not play correctly, but will still reward the item * Ruxxtin Coffin cutscene will sometimes not play correctly, but will still reward the item
* If you receive the Fairy Bottle while in Quillshroom Marsh, The Decurse Queen cutscene will not play. You can exit * If you receive the Fairy Bottle while in Quillshroom Marsh, The De-curse Queen cutscene will not play. You can exit
to Searing Crags and re-enter to get it to play correctly. to Searing Crags and re-enter to get it to play correctly.
* If you defeat Barma'thazël, the cutscene afterward will not play correctly since that is what normally transitions * If you defeat Barma'thazël, the cutscene afterward will not play correctly since that is what normally transitions
you to 2nd quest. The game will not kill you if you fall here, so you can teleport to HQ at any point after defeating him. you to 2nd quest. The game will not kill you if you fall here, so you can teleport to HQ at any point after defeating him.
* Sometimes upon teleporting back to HQ, Ninja will run left and enter a different portal than the one entered by the * Sometimes upon teleporting back to HQ, Ninja will run left and enter a different portal than the one entered by the
player. player. This may also cause a softlock.
* Text entry menus don't accept controller input * Text entry menus don't accept controller input
* Opening the shop chest in power seal hunt mode from the tower of time HQ will soft lock the game. * Opening the shop chest in power seal hunt mode from the tower of time HQ will softlock the game.
## What do I do if I have a problem? ## What do I do if I have a problem?
If you believe something happened that isn't intended, please get the `log.txt`from the folder of your game installation If you believe something happened that isn't intended, please get the `log.txt`from the folder of your game installation
and send a bug report either on github or the [Archipelago Discord Server](http://archipelago.gg/discord) and send a bug report either on GitHub or the [Archipelago Discord Server](http://archipelago.gg/discord)

View File

@ -10,10 +10,11 @@
## Installation ## Installation
1. Download and install Courier Mod Loader using the instructions on the release page 1. Read the [Game Info Page](../../../../games/The%20Messenger/info/en) for how the game works, caveats and known issues
2. Download and install Courier Mod Loader using the instructions on the release page
* [Latest release is currently 0.7.1](https://github.com/Brokemia/Courier/releases) * [Latest release is currently 0.7.1](https://github.com/Brokemia/Courier/releases)
2. Download and install the randomizer mod 3. Download and install the randomizer mod
1. Download the latest TheMessengerRandomizerAP.zip from the 1. Download the latest TheMessengerRandomizerAP.zip from
[The Messenger Randomizer Mod AP releases page](https://github.com/alwaysintreble/TheMessengerRandomizerModAP/releases) [The Messenger Randomizer Mod AP releases page](https://github.com/alwaysintreble/TheMessengerRandomizerModAP/releases)
2. Extract the zip file to `TheMessenger/Mods/` of your game's install location 2. Extract the zip file to `TheMessenger/Mods/` of your game's install location
* You cannot have both the non-AP randomizer and the AP randomizer installed at the same time. The AP randomizer * You cannot have both the non-AP randomizer and the AP randomizer installed at the same time. The AP randomizer
@ -35,10 +36,10 @@
2. Navigate to `Options > Third Party Mod Options` 2. Navigate to `Options > Third Party Mod Options`
3. Select `Reset Randomizer File Slots` 3. Select `Reset Randomizer File Slots`
* This will set up all of your save slots with new randomizer save files. You can have up to 3 randomizer files at a * This will set up all of your save slots with new randomizer save files. You can have up to 3 randomizer files at a
time, but must do this step again to start new runs afterwards. time, but must do this step again to start new runs afterward.
4. Enter connection info using the relevant option buttons 4. Enter connection info using the relevant option buttons
* **The game is limited to alphanumerical characters and `-` so when entering the host name replace `.` with ` ` and * **The game is limited to alphanumerical characters and `-` so when entering the host name replace `.` with ` `.
ensure that your player name when generating a settings file follows these constrictions** Ensure that your player name when generating a settings file follows these constrictions**
* This defaults to `archipelago.gg` and does not need to be manually changed if connecting to a game hosted on the * This defaults to `archipelago.gg` and does not need to be manually changed if connecting to a game hosted on the
website. website.
5. Select the `Connect to Archipelago` button 5. Select the `Connect to Archipelago` button

View File

@ -35,7 +35,7 @@ class AccessTest(MessengerTestBase):
"Tower of Time Seal - Lantern Climb", "Tower of Time Seal - Arcane Orbs", "Tower of Time Seal - Lantern Climb", "Tower of Time Seal - Arcane Orbs",
"Underworld Seal - Sharp and Windy Climb", "Underworld Seal - Fireball Wave", "Underworld Seal - Sharp and Windy Climb", "Underworld Seal - Fireball Wave",
"Elemental Skylands Seal - Air", "Forlorn Temple Seal - Rocket Maze", "Elemental Skylands Seal - Air", "Forlorn Temple Seal - Rocket Maze",
"Forlorn Temple Seal - Rocket Sunset", "Astral Seed"] "Forlorn Temple Seal - Rocket Sunset", "Astral Seed", "Astral Tea Leaves"]
items = [["Wingsuit"]] items = [["Wingsuit"]]
self.assertAccessDependency(locations, items) self.assertAccessDependency(locations, items)
@ -116,7 +116,7 @@ class AccessTest(MessengerTestBase):
class ItemsAccessTest(MessengerTestBase): class ItemsAccessTest(MessengerTestBase):
options = { options = {
"shuffle_seals": "false", "shuffle_seals": "false",
"accessibility": "items" "accessibility": "items",
} }
def testSelfLockingItems(self) -> None: def testSelfLockingItems(self) -> None:

View File

@ -4,7 +4,7 @@ from . import MessengerTestBase
class HardLogicTest(MessengerTestBase): class HardLogicTest(MessengerTestBase):
options = { options = {
"logic_level": "hard" "logic_level": "hard",
} }
def testVertical(self) -> None: def testVertical(self) -> None:
@ -14,7 +14,7 @@ class HardLogicTest(MessengerTestBase):
"Tower of Time Seal - Time Waster Seal", "Tower of Time Seal - Lantern Climb", "Tower of Time Seal - Time Waster Seal", "Tower of Time Seal - Lantern Climb",
"Tower of Time Seal - Arcane Orbs", "Tower of Time Seal - Arcane Orbs",
# ninja village # ninja village
"Candle", "Astral Seed", "Ninja Village Seal - Tree House", "Candle", "Astral Seed", "Ninja Village Seal - Tree House", "Astral Tea Leaves",
# autumn hills # autumn hills
"Climbing Claws", "Key of Hope", "Climbing Claws", "Key of Hope",
"Autumn Hills Seal - Trip Saws", "Autumn Hills Seal - Double Swing Saws", "Autumn Hills Seal - Trip Saws", "Autumn Hills Seal - Double Swing Saws",
@ -54,7 +54,7 @@ class HardLogicTest(MessengerTestBase):
windmill_locs = [ windmill_locs = [
"Key of Strength", "Key of Strength",
"Key of Symbiosis", "Key of Symbiosis",
"Underworld Seal - Fireball Wave" "Underworld Seal - Fireball Wave",
] ]
for loc in windmill_locs: for loc in windmill_locs:
with self.subTest("can't reach location with nothing", location=loc): with self.subTest("can't reach location with nothing", location=loc):
@ -80,13 +80,13 @@ class HardLogicTest(MessengerTestBase):
class ChallengingLogicTest(MessengerTestBase): class ChallengingLogicTest(MessengerTestBase):
options = { options = {
"shuffle_seals": "false", "shuffle_seals": "false",
"logic_level": "challenging" "logic_level": "challenging",
} }
class NoLogicTest(MessengerTestBase): class NoLogicTest(MessengerTestBase):
options = { options = {
"logic_level": "oob" "logic_level": "oob",
} }
def testAccess(self) -> None: def testAccess(self) -> None: