From cf5b3bc9163d68932f5689b047e1b6005bb23641 Mon Sep 17 00:00:00 2001 From: morgan Date: Thu, 13 Nov 2025 21:12:43 -0700 Subject: [PATCH] Adding weights for filler and traps --- worlds/grinch/__init__.py | 75 +++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/worlds/grinch/__init__.py b/worlds/grinch/__init__.py index 96f6c5f5..775cb8e2 100644 --- a/worlds/grinch/__init__.py +++ b/worlds/grinch/__init__.py @@ -1,6 +1,14 @@ +import math from BaseClasses import Region, Item, ItemClassification from .Locations import grinch_locations_to_id, grinch_locations, GrinchLocation, get_location_names_per_category -from .Items import grinch_items_to_id, GrinchItem, ALL_ITEMS_TABLE, MISC_ITEMS_TABLE, get_item_names_per_category, TRAPS_TABLE +from .Items import ( + grinch_items_to_id, + GrinchItem, + ALL_ITEMS_TABLE, + MISC_ITEMS_TABLE, + get_item_names_per_category, + TRAPS_TABLE, +) from .Regions import connect_regions from .Rules import set_location_rules @@ -18,24 +26,25 @@ class GrinchWorld(World): game: ClassVar[str] = "The Grinch" options_dataclass = Options.GrinchOptions options: Options.GrinchOptions - topology_present = True #not an open world game, very linear - item_name_to_id: ClassVar[dict[str,int]] = grinch_items_to_id() - location_name_to_id: ClassVar[dict[str,int]] = grinch_locations_to_id() + topology_present = True # not an open world game, very linear + item_name_to_id: ClassVar[dict[str, int]] = grinch_items_to_id() + location_name_to_id: ClassVar[dict[str, int]] = grinch_locations_to_id() required_client_version = (0, 6, 3) item_name_groups = get_item_names_per_category() location_name_groups = get_location_names_per_category() - def __init__(self, *args, **kwargs): #Pulls __init__ function and takes control from there in BaseClasses.py + def __init__(self, *args, **kwargs): # Pulls __init__ function and takes control from there in BaseClasses.py self.origin_region_name: str = "Mount Crumpit" super(GrinchWorld, self).__init__(*args, **kwargs) - def generate_early(self) -> None: #Special conditions changed before generation occurs + def generate_early(self) -> None: # Special conditions changed before generation occurs if self.options.ring_link == 1 and self.options.unlimited_eggs == 1: - raise OptionError("Cannot enable both unlimited rotten eggs and ring links. You can only enable one of these at a time." + - f"The following player's YAML needs to be fixed: {self.player_name}") + raise OptionError( + "Cannot enable both unlimited rotten eggs and ring links. You can only enable one of these at a time." + + f"The following player's YAML needs to be fixed: {self.player_name}" + ) - - def create_regions(self): #Generates all regions for the multiworld + def create_regions(self): # Generates all regions for the multiworld for region_name in access_rules_dict.keys(): self.multiworld.regions.append(Region(region_name, self.player, self.multiworld)) self.multiworld.regions.append(Region("Mount Crumpit", self.player, self.multiworld)) @@ -47,12 +56,12 @@ class GrinchWorld(World): region.locations.append(entry) connect_regions(self) - def create_item(self, item: str) -> GrinchItem: #Creates specific items on demand + def create_item(self, item: str) -> GrinchItem: # Creates specific items on demand if item in ALL_ITEMS_TABLE.keys(): return GrinchItem(item, self.player, ALL_ITEMS_TABLE[item]) raise Exception(f"Invalid item name: {item}") - def create_items(self): #Generates all items for the multiworld + def create_items(self): # Generates all items for the multiworld self_itempool: list[GrinchItem] = [] for item, data in ALL_ITEMS_TABLE.items(): self_itempool.append(self.create_item(item)) @@ -60,49 +69,55 @@ class GrinchWorld(World): for _ in range(3): self_itempool.append(self.create_item(item)) +<<<<<<< HEAD #Get number of current unfilled locations unfilled_locations: int = ( len(self.multiworld.get_unfilled_locations(self.player)) - len(self_itempool) ) +======= + # Get number of current unfilled locations + unfilled_locations: int = ( + len(self.multiworld.get_unfilled_locations(self.player)) - len(ALL_ITEMS_TABLE.keys()) - 3 + ) + + filler_locations: int = math.floor(unfilled_locations * (1 - (self.options.trap_percentage / 100))) + trap_locations: int = math.floor(unfilled_locations * (self.options.trap_percentage / 100)) + + # This catches the extra 1 or 2 unfilled_locations that come up from the math.floor() + extra_locations = unfilled_locations - (filler_locations + trap_locations) + filler_locations != extra_locations +>>>>>>> 31333183 (Adding weights for filler and traps) # Total available weight sum total_fillerweights = sum(self.options.filler_weight[filler] for filler in MISC_ITEMS_TABLE) # Fill remaining locations according to weight ratio for filler in MISC_ITEMS_TABLE: + # This ratio is a decimal between 0 and 1, and when multiplied by 100 is the % of that filler + # item in the available unfilled locations filler_weight_ratio = self.options.filler_weight[filler] / total_fillerweights - filler_count = round(unfilled_locations * filler_weight_ratio) + filler_count = round(filler_locations * filler_weight_ratio) + for _ in range(filler_count): self_itempool.append(self.create_item(filler)) - # Make sure we don't underfill (in case of rounding losses) - while len(self_itempool) < unfilled_locations: - self_itempool.append(self.create_item(self.get_other_filler_item(list(MISC_ITEMS_TABLE.keys())))) - - # for _ in range(unfilled_locations): - # self_itempool.append(self.create_item((self.get_other_filler_item(list(MISC_ITEMS_TABLE.keys()))))) - # self.multiworld.itempool += self_itempool + # # Make sure we don't underfill (in case of rounding losses) + # while len(self_itempool) < unfilled_locations: + # self_itempool.append(self.create_item(self.get_other_filler_item(list(MISC_ITEMS_TABLE.keys())))) # Total available weight sum if self.options.trap_percentage > 0: total_trapweights = sum(self.options.trap_weight[trap] for trap in TRAPS_TABLE) - if total_trapweights <= 0: + if self.options.trap_percentage > 0 && total_trapweights <= 0: raise Exception("ERROR: Traps are enabled, but all trap weights are zero or undefined") - # Total traps to generate (percentage of unfilled locations) - total_traps = round(unfilled_locations * (self.options.trap_percentage / 100)) - for trap in TRAPS_TABLE: trap_weight_ratio = self.options.trap_weight[trap] / total_trapweights - trap_count = round(total_traps * trap_weight_ratio) + trap_count = round(trap_locations * trap_weight_ratio) for _ in range(trap_count): self_itempool.append(self.create_item(trap)) - # Handle rounding differences - while len(self_itempool) < total_traps: - self_itempool.append(self.create_item(self.get_other_filler_item(list(TRAPS_TABLE.keys())))) - self.multiworld.itempool += self_itempool def set_rules(self): @@ -120,4 +135,4 @@ class GrinchWorld(World): def generate_output(self, output_directory: str) -> None: # print("") - pass \ No newline at end of file + pass