Skip to content

Commit

Permalink
The Messenger: Fix precollected notes not being removed from the item…
Browse files Browse the repository at this point in the history
…pool (ArchipelagoMW#3066)

* The Messenger: fix precollected notes not being properly removed from pool

* The Messenger: bump required client version
  • Loading branch information
alwaysintreble authored Mar 31, 2024
1 parent 72c5351 commit 4e3d396
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 10 deletions.
32 changes: 22 additions & 10 deletions worlds/messenger/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from datetime import date
from typing import Any, ClassVar, Dict, List, Optional, TextIO

from BaseClasses import CollectionState, Entrance, Item, ItemClassification, MultiWorld, Tutorial
Expand All @@ -9,7 +10,8 @@
from worlds.LauncherComponents import Component, Type, components
from .client_setup import launch_game
from .connections import CONNECTIONS, RANDOMIZED_CONNECTIONS, TRANSITIONS
from .constants import ALL_ITEMS, ALWAYS_LOCATIONS, BOSS_LOCATIONS, FILLER, NOTES, PHOBEKINS, PROG_ITEMS, USEFUL_ITEMS
from .constants import ALL_ITEMS, ALWAYS_LOCATIONS, BOSS_LOCATIONS, FILLER, NOTES, PHOBEKINS, PROG_ITEMS, TRAPS, \
USEFUL_ITEMS
from .options import AvailablePortals, Goal, Logic, MessengerOptions, NotesNeeded, ShuffleTransitions
from .portals import PORTALS, add_closed_portal_reqs, disconnect_portals, shuffle_portals, validate_portals
from .regions import LEVELS, MEGA_SHARDS, LOCATIONS, REGION_CONNECTIONS
Expand Down Expand Up @@ -110,7 +112,7 @@ class MessengerWorld(World):
},
}

required_client_version = (0, 4, 3)
required_client_version = (0, 4, 4)

web = MessengerWeb()

Expand All @@ -127,6 +129,7 @@ class MessengerWorld(World):
portal_mapping: List[int]
transitions: List[Entrance]
reachable_locs: int = 0
filler: Dict[str, int]

def generate_early(self) -> None:
if self.options.goal == Goal.option_power_seal_hunt:
Expand All @@ -146,15 +149,20 @@ def generate_early(self) -> None:
self.starting_portals = [f"{portal} Portal"
for portal in starting_portals[:3] +
self.random.sample(starting_portals[3:], k=self.options.available_portals - 3)]

# super complicated method for adding searing crags to starting portals if it wasn't chosen
# need to add a check for transition shuffle when that gets added back in
# TODO add a check for transition shuffle when that gets added back in
if not self.options.shuffle_portals and "Searing Crags Portal" not in self.starting_portals:
self.starting_portals.append("Searing Crags Portal")
if len(self.starting_portals) > 4:
portals_to_strip = [portal for portal in ["Riviere Turquoise Portal", "Sunken Shrine Portal"]
if portal in self.starting_portals]
self.starting_portals.remove(self.random.choice(portals_to_strip))

self.filler = FILLER.copy()
if (not hasattr(self.options, "traps") and date.today() < date(2024, 4, 2)) or self.options.traps:
self.filler.update(TRAPS)

self.plando_portals = []
self.portal_mapping = []
self.spoiler_portal_mapping = {}
Expand Down Expand Up @@ -182,12 +190,13 @@ def create_regions(self) -> None:
def create_items(self) -> None:
# create items that are always in the item pool
main_movement_items = ["Rope Dart", "Wingsuit"]
precollected_names = [item.name for item in self.multiworld.precollected_items[self.player]]
itempool: List[MessengerItem] = [
self.create_item(item)
for item in self.item_name_to_id
if "Time Shard" not in item and item not in {
if item not in {
"Power Seal", *NOTES, *FIGURINES, *main_movement_items,
*{collected_item.name for collected_item in self.multiworld.precollected_items[self.player]},
*precollected_names, *FILLER, *TRAPS,
}
]

Expand All @@ -199,7 +208,7 @@ def create_items(self) -> None:
if self.options.goal == Goal.option_open_music_box:
# make a list of all notes except those in the player's defined starting inventory, and adjust the
# amount we need to put in the itempool and precollect based on that
notes = [note for note in NOTES if note not in self.multiworld.precollected_items[self.player]]
notes = [note for note in NOTES if note not in precollected_names]
self.random.shuffle(notes)
precollected_notes_amount = NotesNeeded.range_end - \
self.options.notes_needed - \
Expand Down Expand Up @@ -228,8 +237,8 @@ def create_items(self) -> None:
remaining_fill = len(self.multiworld.get_unfilled_locations(self.player)) - len(itempool)
if remaining_fill < 10:
self._filler_items = self.random.choices(
list(FILLER)[2:],
weights=list(FILLER.values())[2:],
list(self.filler)[2:],
weights=list(self.filler.values())[2:],
k=remaining_fill
)
filler = [self.create_filler() for _ in range(remaining_fill)]
Expand Down Expand Up @@ -300,8 +309,8 @@ def fill_slot_data(self) -> Dict[str, Any]:
def get_filler_item_name(self) -> str:
if not getattr(self, "_filler_items", None):
self._filler_items = [name for name in self.random.choices(
list(FILLER),
weights=list(FILLER.values()),
list(self.filler),
weights=list(self.filler.values()),
k=20
)]
return self._filler_items.pop(0)
Expand Down Expand Up @@ -335,6 +344,9 @@ def get_item_classification(self, name: str) -> ItemClassification:

if name in {*USEFUL_ITEMS, *USEFUL_SHOP_ITEMS}:
return ItemClassification.useful

if name in TRAPS:
return ItemClassification.trap

return ItemClassification.filler

Expand Down
7 changes: 7 additions & 0 deletions worlds/messenger/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@
"Time Shard (500)": 5,
}

TRAPS = {
"Teleport Trap": 5,
"Prophecy Trap": 10,
}

# item_name_to_id needs to be deterministic and match upstream
ALL_ITEMS = [
*NOTES,
Expand All @@ -71,6 +76,8 @@
*SHOP_ITEMS,
*FIGURINES,
"Money Wrench",
"Teleport Trap",
"Prophecy Trap",
]

# locations
Expand Down
9 changes: 9 additions & 0 deletions worlds/messenger/options.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from dataclasses import dataclass
from datetime import date
from typing import Dict

from schema import And, Optional, Or, Schema
Expand Down Expand Up @@ -123,6 +124,11 @@ class RequiredSeals(Range):
default = range_end


class Traps(Toggle):
"""Whether traps should be included in the itempool."""
display_name = "Include Traps"


class ShopPrices(Range):
"""Percentage modifier for shuffled item prices in shops"""
display_name = "Shop Prices Modifier"
Expand Down Expand Up @@ -199,3 +205,6 @@ class MessengerOptions(DeathLinkMixin, PerGameCommonOptions):
percent_seals_required: RequiredSeals
shop_price: ShopPrices
shop_price_plan: PlannedShopPrices

if date.today() > date(2024, 4, 1):
traps: Traps

0 comments on commit 4e3d396

Please sign in to comment.