From 3eadf54bf3b63e7d073ae7d6a8f28ca92178a6cb Mon Sep 17 00:00:00 2001 From: massimilianodelliubaldini <8584296+massimilianodelliubaldini@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:23:28 -0400 Subject: [PATCH] Added a host.yaml option to override friendly limits, plus a couple of code review updates. --- worlds/jakanddaxter/Client.py | 1 + worlds/jakanddaxter/Rules.py | 11 ++--- worlds/jakanddaxter/__init__.py | 46 +++++++++++++------ .../jakanddaxter/regs/RockVillageRegions.py | 12 ++--- .../regs/SandoverVillageRegions.py | 10 ++-- .../regs/VolcanicCraterRegions.py | 14 +++--- 6 files changed, 53 insertions(+), 41 deletions(-) diff --git a/worlds/jakanddaxter/Client.py b/worlds/jakanddaxter/Client.py index 2c8c9b9962..e15e188fe4 100644 --- a/worlds/jakanddaxter/Client.py +++ b/worlds/jakanddaxter/Client.py @@ -107,6 +107,7 @@ class JakAndDaxterContext(CommonContext): if password_requested and not self.password: await super(JakAndDaxterContext, self).server_auth(password_requested) await self.get_username() + self.tags = set() await self.send_connect() def on_package(self, cmd: str, args: dict): diff --git a/worlds/jakanddaxter/Rules.py b/worlds/jakanddaxter/Rules.py index 4acd02fdb5..4acff95145 100644 --- a/worlds/jakanddaxter/Rules.py +++ b/worlds/jakanddaxter/Rules.py @@ -174,11 +174,10 @@ def enforce_multiplayer_limits(options: JakAndDaxterOptions): f"{friendly_message}") -def verify_orb_trade_amounts(options: JakAndDaxterOptions): +def verify_orb_trade_amounts(world: JakAndDaxterWorld): - total_trade_orbs = (9 * options.citizen_orb_trade_amount) + (6 * options.oracle_orb_trade_amount) - if total_trade_orbs > 2000: - raise OptionError(f"Required number of orbs for all trades ({total_trade_orbs}) " + if world.total_trade_orbs > 2000: + raise OptionError(f"Required number of orbs for all trades ({world.total_trade_orbs}) " f"is more than all the orbs in the game (2000). " - f"Reduce the value of either {options.citizen_orb_trade_amount.display_name} " - f"or {options.oracle_orb_trade_amount.display_name}.") + f"Reduce the value of either {world.options.citizen_orb_trade_amount.display_name} " + f"or {world.options.oracle_orb_trade_amount.display_name}.") diff --git a/worlds/jakanddaxter/__init__.py b/worlds/jakanddaxter/__init__.py index dd04599b7d..1983a276f3 100644 --- a/worlds/jakanddaxter/__init__.py +++ b/worlds/jakanddaxter/__init__.py @@ -1,8 +1,13 @@ -from typing import Dict, Any, ClassVar, Tuple, Callable, Optional +from typing import Dict, Any, ClassVar, Tuple, Callable, Optional, Union + +import Utils import settings from Utils import local_path -from BaseClasses import Item, ItemClassification, Tutorial, CollectionState +from BaseClasses import (Item, + ItemClassification as ItemClass, + Tutorial, + CollectionState) from .GameID import jak1_id, jak1_name, jak1_max from .JakAndDaxterOptions import JakAndDaxterOptions, EnableOrbsanity from .Locations import (JakAndDaxterLocation, @@ -48,7 +53,13 @@ class JakAndDaxterSettings(settings.Group): Ensure this path contains forward slashes (/) only.""" description = "ArchipelaGOAL Root Directory" + class EnforceFriendlyOptions(settings.Bool): + """Enforce friendly player options to be used in a multiplayer seed. + Disabling this allows for more disruptive and challenging options, but may impact seed generation.""" + description = "ArchipelaGOAL Enforce Friendly Options" + root_directory: RootDirectory = RootDirectory("%appdata%/OpenGOAL-Mods/archipelagoal") + enforce_friendly_options: Union[EnforceFriendlyOptions, bool] = True class JakAndDaxterWebWorld(WebWorld): @@ -107,23 +118,27 @@ class JakAndDaxterWorld(World): {11, 12, 31, 32, 33, 96, 97, 98, 99, 13, 14, 34, 35, 100, 101}}, } - # Functions and Variables that are Options-driven, keep them as instance variables here so that we don't clog up + # These functions and variables are Options-driven, keep them as instance variables here so that we don't clog up # the seed generation routines with options checking. So we set these once, and then just use them as needed. can_trade: Callable[[CollectionState, int, Optional[int]], bool] - orb_bundle_size: int = 0 orb_bundle_item_name: str = "" + orb_bundle_size: int = 0 + total_trade_orbs: int = 0 + # Handles various options validation, rules enforcement, and caching of important information. def generate_early(self) -> None: # For the fairness of other players in a multiworld game, enforce some friendly limitations on our options, # so we don't cause chaos during seed generation. These friendly limits should **guarantee** a successful gen. - if self.multiworld.players > 1: + enforce_friendly_options = Utils.get_settings()["jakanddaxter_options"]["enforce_friendly_options"] + if self.multiworld.players > 1 and enforce_friendly_options: from .Rules import enforce_multiplayer_limits enforce_multiplayer_limits(self.options) # Verify that we didn't overload the trade amounts with more orbs than exist in the world. # This is easy to do by accident even in a single-player world. + self.total_trade_orbs = (9 * self.options.citizen_orb_trade_amount) + (6 * self.options.oracle_orb_trade_amount) from .Rules import verify_orb_trade_amounts - verify_orb_trade_amounts(self.options) + verify_orb_trade_amounts(self) # Cache the orb bundle size and item name for quicker reference. if self.options.enable_orbsanity == EnableOrbsanity.option_per_level: @@ -146,36 +161,39 @@ class JakAndDaxterWorld(World): # visualize_regions(self.multiworld.get_region("Menu", self.player), "jakanddaxter.puml") # Helper function to reuse some nasty if/else trees. - def item_type_helper(self, item) -> Tuple[int, ItemClassification]: + def item_type_helper(self, item) -> Tuple[int, ItemClass]: # Make 101 Power Cells. if item in range(jak1_id, jak1_id + Scouts.fly_offset): - classification = ItemClassification.progression_skip_balancing + classification = ItemClass.progression_skip_balancing count = 101 # Make 7 Scout Flies per level. elif item in range(jak1_id + Scouts.fly_offset, jak1_id + Specials.special_offset): - classification = ItemClassification.progression_skip_balancing + classification = ItemClass.progression_skip_balancing count = 7 # Make only 1 of each Special Item. elif item in range(jak1_id + Specials.special_offset, jak1_id + Caches.orb_cache_offset): - classification = ItemClassification.progression + classification = ItemClass.progression | ItemClass.useful count = 1 # Make only 1 of each Move Item. elif item in range(jak1_id + Caches.orb_cache_offset, jak1_id + Orbs.orb_offset): - classification = ItemClassification.progression + classification = ItemClass.progression | ItemClass.useful count = 1 # Make N Precursor Orb bundles, where N is 2000 / bundle size. elif item in range(jak1_id + Orbs.orb_offset, jak1_max): - classification = ItemClassification.progression_skip_balancing + if self.total_trade_orbs == 0: + classification = ItemClass.filler # If you don't need orbs to do trades, they are useless. + else: + classification = ItemClass.progression_skip_balancing count = 2000 // self.orb_bundle_size if self.orb_bundle_size > 0 else 0 # Don't divide by zero! # Under normal circumstances, we will create 0 filler items. # We will manually create filler items as needed. elif item == jak1_max: - classification = ItemClassification.filler + classification = ItemClass.filler count = 0 # If we try to make items with ID's higher than we've defined, something has gone wrong. @@ -193,7 +211,7 @@ class JakAndDaxterWorld(World): # then fill the item pool with a corresponding amount of filler items. if item_name in self.item_name_groups["Moves"] and not self.options.enable_move_randomizer: self.multiworld.push_precollected(self.create_item(item_name)) - self.multiworld.itempool += [self.create_filler()] + self.multiworld.itempool.append(self.create_filler()) continue # Handle Orbsanity option. diff --git a/worlds/jakanddaxter/regs/RockVillageRegions.py b/worlds/jakanddaxter/regs/RockVillageRegions.py index 113fbb79f7..706c44bc16 100644 --- a/worlds/jakanddaxter/regs/RockVillageRegions.py +++ b/worlds/jakanddaxter/regs/RockVillageRegions.py @@ -10,15 +10,13 @@ def build_regions(level_name: str, world: JakAndDaxterWorld) -> List[JakAndDaxte options = world.options player = world.player - total_trade_orbs = (9 * options.citizen_orb_trade_amount) + (6 * options.oracle_orb_trade_amount) - # This includes most of the area surrounding LPC as well, for orb_count purposes. You can swim and single jump. main_area = JakAndDaxterRegion("Main Area", player, multiworld, level_name, 23) - main_area.add_cell_locations([31], access_rule=lambda state: world.can_trade(state, total_trade_orbs, None)) - main_area.add_cell_locations([32], access_rule=lambda state: world.can_trade(state, total_trade_orbs, None)) - main_area.add_cell_locations([33], access_rule=lambda state: world.can_trade(state, total_trade_orbs, None)) - main_area.add_cell_locations([34], access_rule=lambda state: world.can_trade(state, total_trade_orbs, None)) - main_area.add_cell_locations([35], access_rule=lambda state: world.can_trade(state, total_trade_orbs, 34)) + main_area.add_cell_locations([31], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, None)) + main_area.add_cell_locations([32], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, None)) + main_area.add_cell_locations([33], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, None)) + main_area.add_cell_locations([34], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, None)) + main_area.add_cell_locations([35], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, 34)) # These 2 scout fly boxes can be broken by running with nearby blue eco. main_area.add_fly_locations([196684, 262220]) diff --git a/worlds/jakanddaxter/regs/SandoverVillageRegions.py b/worlds/jakanddaxter/regs/SandoverVillageRegions.py index 72ee7bc1d5..a42e3a0b2b 100644 --- a/worlds/jakanddaxter/regs/SandoverVillageRegions.py +++ b/worlds/jakanddaxter/regs/SandoverVillageRegions.py @@ -10,14 +10,12 @@ def build_regions(level_name: str, world: JakAndDaxterWorld) -> List[JakAndDaxte options = world.options player = world.player - total_trade_orbs = (9 * options.citizen_orb_trade_amount) + (6 * options.oracle_orb_trade_amount) - main_area = JakAndDaxterRegion("Main Area", player, multiworld, level_name, 26) # Yakows requires no combat. main_area.add_cell_locations([10]) - main_area.add_cell_locations([11], access_rule=lambda state: world.can_trade(state, total_trade_orbs, None)) - main_area.add_cell_locations([12], access_rule=lambda state: world.can_trade(state, total_trade_orbs, None)) + main_area.add_cell_locations([11], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, None)) + main_area.add_cell_locations([12], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, None)) # These 4 scout fly boxes can be broken by running with all the blue eco from Sentinel Beach. main_area.add_fly_locations([262219, 327755, 131147, 65611]) @@ -35,8 +33,8 @@ def build_regions(level_name: str, world: JakAndDaxterWorld) -> List[JakAndDaxte yakow_cliff.add_fly_locations([75], access_rule=lambda state: can_free_scout_flies(state, player)) oracle_platforms = JakAndDaxterRegion("Oracle Platforms", player, multiworld, level_name, 6) - oracle_platforms.add_cell_locations([13], access_rule=lambda state: world.can_trade(state, total_trade_orbs, None)) - oracle_platforms.add_cell_locations([14], access_rule=lambda state: world.can_trade(state, total_trade_orbs, 13)) + oracle_platforms.add_cell_locations([13], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, None)) + oracle_platforms.add_cell_locations([14], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, 13)) oracle_platforms.add_fly_locations([393291], access_rule=lambda state: can_free_scout_flies(state, player)) diff --git a/worlds/jakanddaxter/regs/VolcanicCraterRegions.py b/worlds/jakanddaxter/regs/VolcanicCraterRegions.py index f772f09c63..11934aa703 100644 --- a/worlds/jakanddaxter/regs/VolcanicCraterRegions.py +++ b/worlds/jakanddaxter/regs/VolcanicCraterRegions.py @@ -11,16 +11,14 @@ def build_regions(level_name: str, world: JakAndDaxterWorld) -> List[JakAndDaxte options = world.options player = world.player - total_trade_orbs = (9 * options.citizen_orb_trade_amount) + (6 * options.oracle_orb_trade_amount) - # No area is inaccessible in VC even with only running and jumping. main_area = JakAndDaxterRegion("Main Area", player, multiworld, level_name, 50) - main_area.add_cell_locations([96], access_rule=lambda state: world.can_trade(state, total_trade_orbs, None)) - main_area.add_cell_locations([97], access_rule=lambda state: world.can_trade(state, total_trade_orbs, 96)) - main_area.add_cell_locations([98], access_rule=lambda state: world.can_trade(state, total_trade_orbs, 97)) - main_area.add_cell_locations([99], access_rule=lambda state: world.can_trade(state, total_trade_orbs, 98)) - main_area.add_cell_locations([100], access_rule=lambda state: world.can_trade(state, total_trade_orbs, None)) - main_area.add_cell_locations([101], access_rule=lambda state: world.can_trade(state, total_trade_orbs, 100)) + main_area.add_cell_locations([96], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, None)) + main_area.add_cell_locations([97], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, 96)) + main_area.add_cell_locations([98], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, 97)) + main_area.add_cell_locations([99], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, 98)) + main_area.add_cell_locations([100], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, None)) + main_area.add_cell_locations([101], access_rule=lambda state: world.can_trade(state, world.total_trade_orbs, 100)) # Hidden Power Cell: you can carry yellow eco from Spider Cave just by running and jumping # and using your Goggles to shoot the box (you do not need Punch to shoot from FP mode).