Skip to content

Commit

Permalink
Merge branch 'main' into mlss-bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesbrq authored Sep 17, 2024
2 parents 0c21fa5 + 5aea8d4 commit 2ff3cd0
Show file tree
Hide file tree
Showing 29 changed files with 147 additions and 59 deletions.
2 changes: 2 additions & 0 deletions BaseClasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ def find_common_pool(players: Set[int], shared_pool: Set[str]) -> Tuple[
region = Region("Menu", group_id, self, "ItemLink")
self.regions.append(region)
locations = region.locations
# ensure that progression items are linked first, then non-progression
self.itempool.sort(key=lambda item: item.advancement)
for item in self.itempool:
count = common_item_count.get(item.player, {}).get(item.name, 0)
if count:
Expand Down
2 changes: 1 addition & 1 deletion CommonClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ def handle_connection_loss(self, msg: str) -> None:
logger.exception(msg, exc_info=exc_info, extra={'compact_gui': True})
self._messagebox_connection_loss = self.gui_error(msg, exc_info[1])

def make_gui(self) -> type:
def make_gui(self) -> typing.Type["kvui.GameManager"]:
"""To return the Kivy App class needed for run_gui so it can be overridden before being built"""
from kvui import GameManager

Expand Down
20 changes: 9 additions & 11 deletions Fill.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,28 +475,26 @@ def mark_for_locking(location: Location):
nonlocal lock_later
lock_later.append(location)

single_player = multiworld.players == 1 and not multiworld.groups

if prioritylocations:
# "priority fill"
fill_restrictive(multiworld, multiworld.state, prioritylocations, progitempool,
single_player_placement=multiworld.players == 1, swap=False, on_place=mark_for_locking,
name="Priority")
single_player_placement=single_player, swap=False, on_place=mark_for_locking, name="Priority")
accessibility_corrections(multiworld, multiworld.state, prioritylocations, progitempool)
defaultlocations = prioritylocations + defaultlocations

if progitempool:
# "advancement/progression fill"
if panic_method == "swap":
fill_restrictive(multiworld, multiworld.state, defaultlocations, progitempool,
swap=True,
name="Progression", single_player_placement=multiworld.players == 1)
fill_restrictive(multiworld, multiworld.state, defaultlocations, progitempool, swap=True,
name="Progression", single_player_placement=single_player)
elif panic_method == "raise":
fill_restrictive(multiworld, multiworld.state, defaultlocations, progitempool,
swap=False,
name="Progression", single_player_placement=multiworld.players == 1)
fill_restrictive(multiworld, multiworld.state, defaultlocations, progitempool, swap=False,
name="Progression", single_player_placement=single_player)
elif panic_method == "start_inventory":
fill_restrictive(multiworld, multiworld.state, defaultlocations, progitempool,
swap=False, allow_partial=True,
name="Progression", single_player_placement=multiworld.players == 1)
fill_restrictive(multiworld, multiworld.state, defaultlocations, progitempool, swap=False,
allow_partial=True, name="Progression", single_player_placement=single_player)
if progitempool:
for item in progitempool:
logging.debug(f"Moved {item} to start_inventory to prevent fill failure.")
Expand Down
3 changes: 2 additions & 1 deletion NetUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,8 @@ def _handle_color(self, node: JSONMessagePart):

color_codes = {'reset': 0, 'bold': 1, 'underline': 4, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33, 'blue': 34,
'magenta': 35, 'cyan': 36, 'white': 37, 'black_bg': 40, 'red_bg': 41, 'green_bg': 42, 'yellow_bg': 43,
'blue_bg': 44, 'magenta_bg': 45, 'cyan_bg': 46, 'white_bg': 47}
'blue_bg': 44, 'magenta_bg': 45, 'cyan_bg': 46, 'white_bg': 47,
'plum': 35, 'slateblue': 34, 'salmon': 31,} # convert ui colors to terminal colors


def color_code(*args):
Expand Down
14 changes: 14 additions & 0 deletions Options.py
Original file line number Diff line number Diff line change
Expand Up @@ -973,14 +973,28 @@ def from_any(cls, data: PlandoTextsFromAnyType) -> Self:
if random.random() < float(text.get("percentage", 100)/100):
at = text.get("at", None)
if at is not None:
if isinstance(at, dict):
if at:
at = random.choices(list(at.keys()),
weights=list(at.values()), k=1)[0]
else:
raise OptionError("\"at\" must be a valid string or weighted list of strings!")
given_text = text.get("text", [])
if isinstance(given_text, dict):
if not given_text:
given_text = []
else:
given_text = random.choices(list(given_text.keys()),
weights=list(given_text.values()), k=1)
if isinstance(given_text, str):
given_text = [given_text]
texts.append(PlandoText(
at,
given_text,
text.get("percentage", 100)
))
else:
raise OptionError("\"at\" must be a valid string or weighted list of strings!")
elif isinstance(text, PlandoText):
if random.random() < float(text.percentage/100):
texts.append(text)
Expand Down
2 changes: 1 addition & 1 deletion Utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def as_simple_string(self) -> str:
return ".".join(str(item) for item in self)


__version__ = "0.5.0"
__version__ = "0.5.1"
version_tuple = tuplize_version(__version__)

is_linux = sys.platform.startswith("linux")
Expand Down
2 changes: 1 addition & 1 deletion docs/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
/worlds/clique/ @ThePhar

# Dark Souls III
/worlds/dark_souls_3/ @Marechal-L
/worlds/dark_souls_3/ @Marechal-L @nex3

# Donkey Kong Country 3
/worlds/dkc3/ @PoryGone
Expand Down
12 changes: 4 additions & 8 deletions worlds/_bizhawk/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,10 @@ def __init__(self, server_address: Optional[str], password: Optional[str]):
self.bizhawk_ctx = BizHawkContext()
self.watcher_timeout = 0.5

def run_gui(self):
from kvui import GameManager

class BizHawkManager(GameManager):
base_title = "Archipelago BizHawk Client"

self.ui = BizHawkManager(self)
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
def make_gui(self):
ui = super().make_gui()
ui.base_title = "Archipelago BizHawk Client"
return ui

def on_package(self, cmd, args):
if cmd == "Connected":
Expand Down
2 changes: 1 addition & 1 deletion worlds/alttp/Options.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ class ALttPPlandoConnections(PlandoConnections):
entrances = set([connection[0] for connection in (
*default_connections, *default_dungeon_connections, *inverted_default_connections,
*inverted_default_dungeon_connections)])
exits = set([connection[1] for connection in (
exits = set([connection[0] for connection in (
*default_connections, *default_dungeon_connections, *inverted_default_connections,
*inverted_default_dungeon_connections)])

Expand Down
4 changes: 1 addition & 3 deletions worlds/blasphemous/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,6 @@ def create_items(self):

self.multiworld.itempool += pool


def pre_fill(self):
self.place_items_from_dict(unrandomized_dict)

if self.options.thorn_shuffle == "vanilla":
Expand Down Expand Up @@ -335,4 +333,4 @@ class BlasphemousItem(Item):


class BlasphemousLocation(Location):
game: str = "Blasphemous"
game: str = "Blasphemous"
2 changes: 1 addition & 1 deletion worlds/hk/docs/setup_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
### What to do if Lumafly fails to find your installation directory
1. Find the directory manually.
* Xbox Game Pass:
1. Enter the XBox app and move your mouse over "Hollow Knight" on the left sidebar.
1. Enter the Xbox app and move your mouse over "Hollow Knight" on the left sidebar.
2. Click the three points then click "Manage".
3. Go to the "Files" tab and select "Browse...".
4. Click "Hollow Knight", then "Content", then click the path bar and copy it.
Expand Down
4 changes: 3 additions & 1 deletion worlds/lingo/data/LL1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,9 @@
Crossroads:
door: Crossroads Entrance
The Tenacious:
door: Tenacious Entrance
- door: Tenacious Entrance
- room: The Tenacious
door: Shortcut to Hub Room
Near Far Area: True
Hedge Maze:
door: Shortcut to Hedge Maze
Expand Down
Binary file modified worlds/lingo/data/generated.dat
Binary file not shown.
2 changes: 1 addition & 1 deletion worlds/mm2/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
minimum_weakness_requirement: Dict[int, int] = {
0: 1, # Mega Buster is free
1: 14, # 2 shots of Atomic Fire
2: 1, # 14 shots of Air Shooter, although you likely hit more than one shot
2: 2, # 14 shots of Air Shooter
3: 4, # 9 uses of Leaf Shield, 3 ends up 1 damage off
4: 1, # 56 uses of Bubble Lead
5: 1, # 224 uses of Quick Boomerang
Expand Down
28 changes: 27 additions & 1 deletion worlds/mmbn3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,28 @@ def create_regions(self) -> None:
add_item_rule(loc, lambda item: not item.advancement)
region.locations.append(loc)
self.multiworld.regions.append(region)

# Regions which contribute to explore score when accessible.
explore_score_region_names = (
RegionName.WWW_Island,
RegionName.SciLab_Overworld,
RegionName.SciLab_Cyberworld,
RegionName.Yoka_Overworld,
RegionName.Yoka_Cyberworld,
RegionName.Beach_Overworld,
RegionName.Beach_Cyberworld,
RegionName.Undernet,
RegionName.Deep_Undernet,
RegionName.Secret_Area,
)
explore_score_regions = [self.get_region(region_name) for region_name in explore_score_region_names]

# Entrances which use explore score in their logic need to register all the explore score regions as indirect
# conditions.
def register_explore_score_indirect_conditions(entrance):
for explore_score_region in explore_score_regions:
self.multiworld.register_indirect_condition(explore_score_region, entrance)

for region_info in regions:
region = name_to_region[region_info.name]
for connection in region_info.connections:
Expand All @@ -119,23 +141,27 @@ def create_regions(self) -> None:
entrance.access_rule = lambda state: \
state.has(ItemName.CSciPas, self.player) or \
state.can_reach(RegionName.SciLab_Overworld, "Region", self.player)
self.multiworld.register_indirect_condition(self.get_region(RegionName.SciLab_Overworld), entrance)
if connection == RegionName.Yoka_Cyberworld:
entrance.access_rule = lambda state: \
state.has(ItemName.CYokaPas, self.player) or \
(
state.can_reach(RegionName.SciLab_Overworld, "Region", self.player) and
state.has(ItemName.Press, self.player)
)
self.multiworld.register_indirect_condition(self.get_region(RegionName.SciLab_Overworld), entrance)
if connection == RegionName.Beach_Cyberworld:
entrance.access_rule = lambda state: state.has(ItemName.CBeacPas, self.player) and\
state.can_reach(RegionName.Yoka_Overworld, "Region", self.player)

self.multiworld.register_indirect_condition(self.get_region(RegionName.Yoka_Overworld), entrance)
if connection == RegionName.Undernet:
entrance.access_rule = lambda state: self.explore_score(state) > 8 and\
state.has(ItemName.Press, self.player)
register_explore_score_indirect_conditions(entrance)
if connection == RegionName.Secret_Area:
entrance.access_rule = lambda state: self.explore_score(state) > 12 and\
state.has(ItemName.Hammer, self.player)
register_explore_score_indirect_conditions(entrance)
if connection == RegionName.WWW_Island:
entrance.access_rule = lambda state:\
state.has(ItemName.Progressive_Undernet_Rank, self.player, 8)
Expand Down
2 changes: 1 addition & 1 deletion worlds/oot/Regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def get_scene(self):
return None

def can_reach(self, state):
if state.stale[self.player]:
if state._oot_stale[self.player]:
stored_age = state.age[self.player]
state._oot_update_age_reachable_regions(self.player)
state.age[self.player] = stored_age
Expand Down
13 changes: 9 additions & 4 deletions worlds/oot/Rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,17 @@
from .Items import oot_is_item_of_type
from .LocationList import dungeon_song_locations

from BaseClasses import CollectionState
from BaseClasses import CollectionState, MultiWorld
from worlds.generic.Rules import set_rule, add_rule, add_item_rule, forbid_item
from ..AutoWorld import LogicMixin


class OOTLogic(LogicMixin):
def init_mixin(self, parent: MultiWorld):
# Separate stale state for OOTRegion.can_reach() to use because CollectionState.update_reachable_regions() sets
# `self.state[player] = False` for all players without updating OOT's age region accessibility.
self._oot_stale = {player: True for player, world in parent.worlds.items()
if parent.worlds[player].game == "Ocarina of Time"}

def _oot_has_stones(self, count, player):
return self.has_group("stones", player, count)
Expand Down Expand Up @@ -92,9 +97,9 @@ def _oot_reach_at_time(self, regionname, tod, already_checked, player):
return False

# Store the age before calling this!
def _oot_update_age_reachable_regions(self, player):
self.stale[player] = False
for age in ['child', 'adult']:
def _oot_update_age_reachable_regions(self, player):
self._oot_stale[player] = False
for age in ['child', 'adult']:
self.age[player] = age
rrp = getattr(self, f'{age}_reachable_regions')[player]
bc = getattr(self, f'{age}_blocked_connections')[player]
Expand Down
9 changes: 7 additions & 2 deletions worlds/oot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1301,6 +1301,7 @@ def write_spoiler(self, spoiler_handle: typing.TextIO) -> None:
# the appropriate number of keys in the collection state when they are
# picked up.
def collect(self, state: CollectionState, item: OOTItem) -> bool:
state._oot_stale[self.player] = True
if item.advancement and item.special and item.special.get('alias', False):
alt_item_name, count = item.special.get('alias')
state.prog_items[self.player][alt_item_name] += count
Expand All @@ -1313,8 +1314,12 @@ def remove(self, state: CollectionState, item: OOTItem) -> bool:
state.prog_items[self.player][alt_item_name] -= count
if state.prog_items[self.player][alt_item_name] < 1:
del (state.prog_items[self.player][alt_item_name])
state._oot_stale[self.player] = True
return True
return super().remove(state, item)
changed = super().remove(state, item)
if changed:
state._oot_stale[self.player] = True
return changed


# Helper functions
Expand Down Expand Up @@ -1389,7 +1394,7 @@ def get_state_with_complete_itempool(self):
# If free_scarecrow give Scarecrow Song
if self.free_scarecrow:
all_state.collect(self.create_item("Scarecrow Song"), prevent_sweep=True)
all_state.stale[self.player] = True
all_state._oot_stale[self.player] = True

return all_state

Expand Down
8 changes: 7 additions & 1 deletion worlds/osrs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ class OSRSWeb(WebWorld):


class OSRSWorld(World):
"""
The best retro fantasy MMORPG on the planet. Old School is RuneScape but… older! This is the open world you know and love, but as it was in 2007.
The Randomizer takes the form of a Chunk-Restricted f2p Ironman that takes a brand new account up through defeating
the Green Dragon of Crandor and earning a spot in the fabled Champion's Guild!
"""

game = "Old School Runescape"
options_dataclass = OSRSOptions
options: OSRSOptions
Expand Down Expand Up @@ -635,7 +641,7 @@ def can_gold(state):
else:
return lambda state: can_tan(state) or (can_silver(state) and can_smelt_silver(state)) or \
(can_gold(state) and can_smelt_gold(state))
if skill.lower() == "Cooking":
if skill.lower() == "cooking":
if self.options.brutal_grinds or level < 15:
return lambda state: state.can_reach(RegionNames.Milk, "Region", self.player) or \
state.can_reach(RegionNames.Egg, "Region", self.player) or \
Expand Down
19 changes: 19 additions & 0 deletions worlds/pokemon_emerald/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
# 2.3.0

### Features

- Added a Swedish translation of the setup guide.
- The client communicates map transitions to any trackers connected to the slot.
- Added the player's Normalize Encounter Rates option to slot data for trackers.

### Fixes

- Fixed a logic issue where the "Mauville City - Coin Case from Lady in House" location only required a Harbor Mail if
the player randomized NPC gifts.
- The Dig tutor has its compatibility percentage raised to 50% if the player's TM/tutor compatibility is set lower.
- A Team Magma Grunt in the Space Center which could become unreachable while trainersanity is active by overlapping
with another NPC was moved to an unoccupied space.
- Fixed a problem where the client would crash on certain operating systems while using certain python versions if the
player tried to wonder trade.

# 2.2.0

### Features
Expand Down Expand Up @@ -175,6 +193,7 @@ turn to face you when you run.
species equally likely to appear, but makes rare encounters less rare.
- Added `Trick House` location group.
- Removed `Postgame Locations` location group.
- Added a Spanish translation of the setup guide.

### QoL

Expand Down
1 change: 1 addition & 0 deletions worlds/pokemon_emerald/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,7 @@ def fill_slot_data(self) -> Dict[str, Any]:
"trainersanity",
"modify_118",
"death_link",
"normalize_encounter_rates",
)
slot_data["free_fly_location_id"] = self.free_fly_location_id
slot_data["hm_requirements"] = self.hm_requirements
Expand Down
Loading

0 comments on commit 2ff3cd0

Please sign in to comment.