From d24d8c6483ace7479030f74b5431554f379eb9e3 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sun, 28 Jul 2024 21:22:23 +0200 Subject: [PATCH 01/20] advanced hint options --- worlds/witness/__init__.py | 9 +- worlds/witness/hints.py | 161 ++++++++++++---------------- worlds/witness/options.py | 210 ++++++++++++++++++++++++++++++++++++- 3 files changed, 280 insertions(+), 100 deletions(-) diff --git a/worlds/witness/__init__.py b/worlds/witness/__init__.py index b228842019cf..baf8ae5b1011 100644 --- a/worlds/witness/__init__.py +++ b/worlds/witness/__init__.py @@ -5,7 +5,7 @@ from logging import error, warning from typing import Any, Dict, List, Optional, cast -from BaseClasses import CollectionState, Entrance, Location, Region, Tutorial +from BaseClasses import CollectionState, Entrance, Location, LocationProgressType, Region, Tutorial from Options import OptionError, PerGameCommonOptions, Toggle from worlds.AutoWorld import WebWorld, World @@ -321,6 +321,13 @@ def fill_slot_data(self) -> Dict[str, Any]: already_hinted_locations = set() + # Excluded locations should never be hinted + + already_hinted_locations |= { + location.name for location in self.multiworld.get_locations(self.player) + if location.progress_type == LocationProgressType.EXCLUDED + } + # Laser hints if self.options.laser_hints: diff --git a/worlds/witness/hints.py b/worlds/witness/hints.py index c8ddf260d4e6..3f20d4d73260 100644 --- a/worlds/witness/hints.py +++ b/worlds/witness/hints.py @@ -3,7 +3,7 @@ from dataclasses import dataclass from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Tuple, Union, cast -from BaseClasses import CollectionState, Item, Location, LocationProgressType, MultiWorld, Region +from BaseClasses import CollectionState, Item, Location, MultiWorld, Region from .data import static_logic as static_witness_logic from .data.utils import weighted_sample @@ -42,132 +42,98 @@ class WitnessWordedHint: def get_always_hint_items(world: "WitnessWorld") -> List[str]: - always = [ - "Boat", - "Caves Shortcuts", - "Progressive Dots", - ] + always = sorted(world.options.always_hint_items.value) difficulty = world.options.puzzle_randomization discards = world.options.shuffle_discarded_panels wincon = world.options.victory_condition - if discards: + if discards and world.options.discard_symbol_hint == "always_hint": if difficulty == "sigma_expert": always.append("Arrows") else: always.append("Triangles") - if wincon == "elevator": - always += ["Mountain Bottom Floor Pillars Room Entry (Door)", "Mountain Bottom Floor Doors"] + if world.options.final_door_hint == "always_hint": + if wincon == "elevator": + always += ["Mountain Bottom Floor Pillars Room Entry (Door)", "Mountain Bottom Floor Doors"] - if wincon == "challenge": - always += ["Challenge Entry (Panel)", "Caves Panels"] + if wincon == "challenge": + always += ["Challenge Entry (Panel)", "Caves Panels", "Challenge Entry (Door)", "Caves Doors"] return always def get_always_hint_locations(world: "WitnessWorld") -> List[str]: - always = [ - "Challenge Vault Box", - "Mountain Bottom Floor Discard", - "Theater Eclipse EP", - "Shipwreck Couch EP", - "Mountainside Cloud Cycle EP", - ] - - # Add Obelisk Sides that contain EPs that are meant to be hinted, if they are necessary to complete the Obelisk Side - if "0x339B6" not in world.player_logic.COMPLETELY_DISABLED_ENTITIES: - always.append("Town Obelisk Side 6") # Eclipse EP + always = sorted(world.options.always_hint_locations.value) - if "0x3388F" not in world.player_logic.COMPLETELY_DISABLED_ENTITIES: - always.append("Treehouse Obelisk Side 4") # Couch EP + # For EPs, also make their obelisk side an always hint + for location_name in always: + location_obj = static_witness_logic.ENTITIES_BY_NAME[location_name] + if location_obj["entityType"] != "EP": + continue + if location_obj["entity_hex"] in world.player_logic.COMPLETELY_DISABLED_ENTITIES: + continue - if "0x335AE" not in world.player_logic.COMPLETELY_DISABLED_ENTITIES: - always.append("Mountainside Obelisk Side 1") # Cloud Cycle EP. + corresponding_obelisk_side = static_witness_logic.EP_TO_OBELISK_SIDE[location_obj["entity_hex"]] + always.append(static_witness_logic.ENTITIES_BY_ID[corresponding_obelisk_side]["checkName"]) return always def get_priority_hint_items(world: "WitnessWorld") -> List[str]: - priority = { - "Caves Mountain Shortcut (Door)", - "Caves Swamp Shortcut (Door)", - "Swamp Entry (Panel)", - "Swamp Laser Shortcut (Door)", - } + priority = world.options.priority_hint_items.value - if world.options.shuffle_symbols: - symbols = [ - "Progressive Dots", - "Progressive Stars", - "Shapers", - "Rotated Shapers", - "Negative Shapers", - "Arrows", - "Triangles", - "Eraser", - "Black/White Squares", - "Colored Squares", - "Sound Dots", - "Progressive Symmetry" - ] + difficulty = world.options.puzzle_randomization + discards = world.options.shuffle_discarded_panels + wincon = world.options.victory_condition - priority.update(world.random.sample(symbols, 5)) - - if world.options.shuffle_lasers: - lasers = [ - "Symmetry Laser", - "Town Laser", - "Keep Laser", - "Swamp Laser", - "Treehouse Laser", - "Monastery Laser", - "Jungle Laser", - "Quarry Laser", - "Bunker Laser", - "Shadows Laser", - ] + if discards and world.options.discard_symbol_hint == "priority_hint": + if difficulty == "sigma_expert": + priority.add("Arrows") + else: + priority.add("Triangles") - if world.options.shuffle_doors >= 2: - priority.add("Desert Laser") - priority.update(world.random.sample(lasers, 5)) + if world.options.final_door_hint == "priority_hint": + if wincon == "elevator": + priority |= {"Mountain Bottom Floor Pillars Room Entry (Door)", "Mountain Bottom Floor Doors"} - else: - lasers.append("Desert Laser") - priority.update(world.random.sample(lasers, 6)) + if wincon == "challenge": + priority |= {"Challenge Entry (Panel)", "Caves Panels", "Challenge Entry (Door)", "Caves Doors"} + + # Add symbols and lasers in accordance with Priority Symbols and Priority Lasers options + + number_of_symbols = sum(item in world.item_name_groups["Symbols"] for item in priority) + number_of_lasers = sum(item in world.item_name_groups["Lasers"] for item in priority) + + needed_symbols = world.options.priority_symbols - number_of_symbols + needed_lasers = world.options.priority_lasers - number_of_lasers + + possible_symbols = sorted(world.item_name_groups["Symbols"] - priority) + possible_lasers = sorted(world.item_name_groups["Lasers"] - priority) + + if needed_symbols > 0: + priority.update(world.random.sample(possible_symbols, needed_symbols)) + + if needed_lasers > 0: + priority.update(world.random.sample(possible_lasers, needed_lasers)) return sorted(priority) def get_priority_hint_locations(world: "WitnessWorld") -> List[str]: - priority = [ - "Tutorial Patio Floor", - "Tutorial Patio Flowers EP", - "Swamp Purple Underwater", - "Shipwreck Vault Box", - "Town RGB House Upstairs Left", - "Town RGB House Upstairs Right", - "Treehouse Green Bridge 7", - "Treehouse Green Bridge Discard", - "Shipwreck Discard", - "Desert Vault Box", - "Mountainside Vault Box", - "Mountainside Discard", - "Tunnels Theater Flowers EP", - "Boat Shipwreck Green EP", - "Quarry Stoneworks Control Room Left", - ] + priority = sorted(world.options.priority_hint_locations.value) - # Add Obelisk Sides that contain EPs that are meant to be hinted, if they are necessary to complete the Obelisk Side - if "0x33A20" not in world.player_logic.COMPLETELY_DISABLED_ENTITIES: - priority.append("Town Obelisk Side 6") # Theater Flowers EP - - if "0x28B29" not in world.player_logic.COMPLETELY_DISABLED_ENTITIES: - priority.append("Treehouse Obelisk Side 4") # Shipwreck Green EP + # For EPs, also make their obelisk side a priority hint + for location_name in priority: + location_obj = static_witness_logic.ENTITIES_BY_NAME[location_name] + if location_obj["entityType"] != "EP": + continue + if location_obj["entity_hex"] in world.player_logic.COMPLETELY_DISABLED_ENTITIES: + continue - if "0x33600" not in world.player_logic.COMPLETELY_DISABLED_ENTITIES: - priority.append("Town Obelisk Side 2") # Tutorial Patio Flowers EP. + corresponding_obelisk_side = static_witness_logic.EP_TO_OBELISK_SIDE[location_obj["entity_hex"]] + priority.append(static_witness_logic.ENTITIES_BY_ID[corresponding_obelisk_side]["checkName"]) return priority @@ -306,7 +272,7 @@ def get_item_and_location_names_in_random_order(world: "WitnessWorld", locations_in_this_world = [ location for location in world.multiworld.get_locations(world.player) - if location.item and not location.is_event and location.progress_type != LocationProgressType.EXCLUDED + if location.item and not location.is_event ] world.random.shuffle(locations_in_this_world) @@ -375,7 +341,7 @@ def make_extra_location_hints(world: "WitnessWorld", hint_amount: int, own_itemp unhinted_locations_for_hinted_areas: Dict[str, Set[Location]]) -> List[WitnessWordedHint]: prog_items_in_this_world, locations_in_this_world = get_item_and_location_names_in_random_order(world, own_itempool) - next_random_hint_is_location = world.random.randrange(0, 2) + next_random_hint_is_location = world.random.randrange(0, 100) >= world.options.random_hints_are_items_weight hints: List[WitnessWordedHint] = [] @@ -626,7 +592,10 @@ def create_all_hints(world: "WitnessWorld", hint_amount: int, area_hints: int, # Make up to half of the rest of the location hints priority hints, using up to half of the possibly priority hints remaining_location_hints = intended_location_hints - always_hints_to_use - priority_hints_to_use = int(max(0.0, min(possible_priority_hints / 2, remaining_location_hints / 2))) + priority_hints_to_use = int(max(0.0, min( + possible_priority_hints * world.options.priority_hints_percentage_out_of_possible / 100, + remaining_location_hints * world.options.priority_hints_percentage_out_of_remaining / 100, + ))) for _ in range(always_hints_to_use): location_hint = always_hints.pop() diff --git a/worlds/witness/options.py b/worlds/witness/options.py index 6f7222d5f9b4..4f358bf4b574 100644 --- a/worlds/witness/options.py +++ b/worlds/witness/options.py @@ -2,8 +2,20 @@ from schema import And, Schema -from Options import Choice, DefaultOnToggle, OptionDict, OptionGroup, PerGameCommonOptions, Range, Toggle, Visibility - +from Options import ( + Choice, + DefaultOnToggle, + ItemSet, + LocationSet, + OptionDict, + OptionGroup, + PerGameCommonOptions, + Range, + Toggle, + Visibility, +) + +from .data import static_items as static_witness_items from .data import static_logic as static_witness_logic from .data.item_definition_classes import ItemCategory, WeightedItemDefinition @@ -390,6 +402,173 @@ class DeathLinkAmnesty(Range): default = 1 +class DiscardSymbolHint(Choice): + """ + Controls whether the symbol required to solve Discarded Panels (Triangles / Arrows) has elevated priority for Audio Log hints. + """ + display_name = "Discarded Panel Symbol Hint" + + option_no_elevated_status = 0 + option_priority_hint = 1 + option_always_hint = 2 + default = 2 + + +class FinalDoorHint(Choice): + """ + Controls whether the door required to enter the final room (dependent on Victory Condition option and Shuffle Doors option) has elevated priority for Audio Log hints. + + For Mountain Box goals, this has no effect. + For Elevator goal, this will only have an effect if playing Remote Door Shuffle, in which case it hints Mountain Bottom Floor Pillars Room Entry (individual) or Mountain Bottom Floor Doors (regional) + For Challenge goal, this will hint Challenge Entry Panel (individual) or Caves Panels (regional) in Panel Door Shuffle, and it will hint Challenge Entry Door (individual) or Caves Doors (regional) in Remote Door Shuffle. + """ + display_name = "Final Door Item Hint" + + option_no_elevated_status = 0 + option_priority_hint = 1 + option_always_hint = 2 + default = 2 + + +class AlwaysHintItems(ItemSet): + """ + Items that will always get an audio log hint if they exist in the itempool. + """ + display_name = "Always Hint Items" + default = { + "Boat", + "Caves Shortcuts", + "Progressive Dots", + } + + +class AlwaysHintLocations(LocationSet): + """ + Locations that will always get an audio log hint if they exist in the world. + + If an individual EP is set, its corresponding Obelisk Side will become an Always Hint as well, if the EP is not disabled (e.g. through the EP Difficulty setting). + """ + display_name = "Always Hint Locations" + default = { + "Challenge Vault Box", + "Mountain Bottom Floor Discard", + "Theater Eclipse EP", + "Shipwreck Couch EP", + "Mountainside Cloud Cycle EP", + } + + +class PriorityHintItems(ItemSet): + """ + Items that will have increased priority to be hinted if they exist in the itempool. + """ + display_name = "Priority Hint Items" + default = { + "Boat", + "Caves Shortcuts", + "Progressive Dots", + } + + +class PriorityHintLocations(LocationSet): + """ + Locations that will have increased priority to be hinted if they exist in the world. + + If an individual EP is set, its corresponding Obelisk Side will become a Priority Hint as well, if the EP is not disabled (e.g. through the EP Difficulty setting). + """ + + display_name = "Priority Hint Locations" + default = { + "Tutorial Patio Floor", + "Tutorial Patio Flowers EP", + "Swamp Purple Underwater", + "Shipwreck Vault Box", + "Town RGB House Upstairs Left", + "Town RGB House Upstairs Right", + "Treehouse Green Bridge 7", + "Treehouse Green Bridge Discard", + "Shipwreck Discard", + "Desert Vault Box", + "Mountainside Vault Box", + "Mountainside Discard", + "Tunnels Theater Flowers EP", + "Boat Shipwreck Green EP", + "Quarry Stoneworks Control Room Left", + } + + +class PrioritySymbols(Range): + """ + Amount of random Symbol items to add to Priority Hints. + If Symbol items have been manually set as Priority Hints elsewhere, e.g. via the Priority Hint Items option, they are counted for this number, and only as many symbols as are necessary are added to meet this value. + Also, if a priority Symbol item is already an Always Hint, it will just be "eaten", this option will not try to dodge them. + """ + display_name = "Priority Symbols" + + range_start = 0 + range_end = len(static_witness_items.ITEM_GROUPS["Symbols"]) + default = 5 + + +class PriorityLasers(Range): + """ + Amount of random Laser items to add to Priority Hints. + If Laser items have been manually set as Priority Hints elsewhere, e.g. via the Priority Hint Items option, they are counted for this number, and only as many symbols as are necessary are added to meet this value. + Also, if a priority Laser item is already an Always Hint, it will just be "eaten", this option will not try to dodge them. + """ + display_name = "Priority Lasers" + + range_start = 0 + range_end = len(static_witness_items.ITEM_GROUPS["Lasers"]) + default = 6 + + +class PriorityHintsPercentageOutOfRemaining(Range): + """ + Maximum percentage of Priority Hints to make. + This percentage refers to the amount of remaining hints after Always and Area hints. + + Example: + The total hint amount is 15. + There are 3 Area Hints and 2 Always Hints. + This option is set to 50%. + This means that the amount of Priority Hints is capped at 5, because the amount of remaining hints after Area Hints and Always Hints is 10, and 50% of 10 is equal to 5. + """ + display_name = "Maximum Priority Hints Percentage (out of Remaining Hints)" + + range_start = 0 + range_end = 100 + default = 50 + + +class PriorityHintsPercentageOutOfPossible(Range): + """ + Maximum percentage of possible Priority Hints to use. + + Example: + The amount of remaining hints after Area Hints and Always Hints is 20. + After evaluating all the Priority Hint options, there are 30 available Priority Hints. + This option is set to 50%. + This means that the amount of Priority Hints is capped at 15, because only 50% of available Priority Hints are allowed to be used. + """ + display_name = "Maximum Priortiy Hints (out of possible Priority Hints)" + + range_start = 0 + range_end = 100 + default = 50 + + +class RandomHintsAreItemHintsWeight(Range): + """ + Controls the chance of Random Hints (after Area Hints, Always Hints and Priority Hints) to be for Items from this world's itempool, rather than Locations in this world. + """ + display_name = "Remaining Hints Are Items Weight" + + range_start = 0 + range_end = 100 + default = 50 + + @dataclass class TheWitnessOptions(PerGameCommonOptions): puzzle_randomization: PuzzleRandomization @@ -425,6 +604,18 @@ class TheWitnessOptions(PerGameCommonOptions): death_link: DeathLink death_link_amnesty: DeathLinkAmnesty + discard_symbol_hint: DiscardSymbolHint + final_door_hint: FinalDoorHint + always_hint_items: AlwaysHintItems + always_hint_locations: AlwaysHintLocations + priority_hint_items: PriorityHintItems + priority_hint_locations: PriorityHintLocations + priority_symbols: PrioritySymbols + priority_lasers: PriorityLasers + priority_hints_percentage_out_of_remaining: PriorityHintsPercentageOutOfRemaining + priority_hints_percentage_out_of_possible: PriorityHintsPercentageOutOfPossible + random_hints_are_items_weight: RandomHintsAreItemHintsWeight + witness_option_groups = [ OptionGroup("Puzzles & Goal", [ @@ -471,5 +662,18 @@ class TheWitnessOptions(PerGameCommonOptions): ElevatorsComeToYou, DeathLink, DeathLinkAmnesty, - ]) + ]), + OptionGroup("Advanced Hint Options", [ + DiscardSymbolHint, + FinalDoorHint, + AlwaysHintItems, + AlwaysHintLocations, + PriorityHintItems, + PriorityHintLocations, + PrioritySymbols, + PriorityLasers, + PriorityHintsPercentageOutOfRemaining, + PriorityHintsPercentageOutOfPossible, + RandomHintsAreItemHintsWeight, + ], start_collapsed=True), ] From d3dd2242a8539e053fd2984aba7753697723a891 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sun, 28 Jul 2024 21:25:37 +0200 Subject: [PATCH 02/20] oops --- worlds/witness/options.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/worlds/witness/options.py b/worlds/witness/options.py index 4f358bf4b574..e2b35069b066 100644 --- a/worlds/witness/options.py +++ b/worlds/witness/options.py @@ -463,11 +463,6 @@ class PriorityHintItems(ItemSet): Items that will have increased priority to be hinted if they exist in the itempool. """ display_name = "Priority Hint Items" - default = { - "Boat", - "Caves Shortcuts", - "Progressive Dots", - } class PriorityHintLocations(LocationSet): From 8cfdc13a516098ac696c285c1195618549fd3497 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sun, 28 Jul 2024 21:56:28 +0200 Subject: [PATCH 03/20] make valid keys --- worlds/witness/__init__.py | 6 ++---- worlds/witness/data/static_items.py | 15 +++++++++++++++ worlds/witness/data/static_locations.py | 23 +++++++++++++++++++++-- worlds/witness/options.py | 9 +++++++++ 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/worlds/witness/__init__.py b/worlds/witness/__init__.py index baf8ae5b1011..29ddc3065ba8 100644 --- a/worlds/witness/__init__.py +++ b/worlds/witness/__init__.py @@ -233,10 +233,8 @@ def create_regions(self) -> None: # Then, add checks in order until the required amount of sphere 1 checks is met. extra_checks = [ - ("Tutorial First Hallway Room", "Tutorial First Hallway Bend"), - ("Tutorial First Hallway", "Tutorial First Hallway Straight"), - ("Desert Outside", "Desert Surface 1"), - ("Desert Outside", "Desert Surface 2"), + (location, static_witness_logic.ENTITIES_BY_NAME[location]["region"]["name"]) + for location in static_witness_locations.EXTRA_LOCATIONS ] for i in range(num_early_locs, needed_size): diff --git a/worlds/witness/data/static_items.py b/worlds/witness/data/static_items.py index b0d8fc3c4f6e..aa5ea52aa538 100644 --- a/worlds/witness/data/static_items.py +++ b/worlds/witness/data/static_items.py @@ -8,11 +8,23 @@ ITEM_DATA: Dict[str, ItemData] = {} ITEM_GROUPS: Dict[str, Set[str]] = {} +POSSIBLE_ITEMS: Set[str] = set() # Useful items that are treated specially at generation time and should not be automatically added to the player's # item list during get_progression_items. _special_usefuls: List[str] = ["Puzzle Skip"] +_impossible_items: Set[str] = { + "Dots", + "Full Dots", + "Symmetry", + "Colored Dots", + "Stars", + "Stars + Same Colored Symbol", + "Invisible Dots" +} + + def populate_items() -> None: for item_name, definition in static_witness_logic.ALL_ITEMS.items(): @@ -43,6 +55,9 @@ def populate_items() -> None: ITEM_DATA[item_name] = ItemData(ap_item_code, definition, classification, local_only) + if item_name not in _impossible_items: + POSSIBLE_ITEMS.add(item_name) + def get_item_to_door_mappings() -> Dict[int, List[int]]: output: Dict[int, List[int]] = {} diff --git a/worlds/witness/data/static_locations.py b/worlds/witness/data/static_locations.py index d9566080a04c..b0a3d9b69e95 100644 --- a/worlds/witness/data/static_locations.py +++ b/worlds/witness/data/static_locations.py @@ -1,6 +1,6 @@ -from typing import Dict, Set, cast +from typing import Dict, Set, cast, List -from . import static_logic as static_witness_logic +from . import static_logic as static_witness_logic, utils ID_START = 158000 @@ -451,6 +451,15 @@ AREA_LOCATION_GROUPS: Dict[str, Set[str]] = {} +POSSIBLE_LOCATIONS: Set[str] = set() + +EXTRA_LOCATIONS: List[str] = [ + "Tutorial First Hallway Bend", + "Tutorial First Hallway Straight", + "Desert Surface 1", + "Desert Surface 2", +] + def get_id(entity_hex: str) -> int: """ @@ -486,3 +495,13 @@ def get_event_name(entity_hex: str) -> str: for loc in ALL_LOCATIONS_TO_IDS: area = static_witness_logic.ENTITIES_BY_NAME[loc]["area"]["name"] AREA_LOCATION_GROUPS.setdefault(area, set()).add(loc) + +POSSIBLE_LOCATIONS |= GENERAL_LOCATIONS +POSSIBLE_LOCATIONS.update(EXTRA_LOCATIONS) + +door_shuffle_line_gen = (line for line in utils.get_complex_doors()) +for line in door_shuffle_line_gen: + if line.startswith("Added Locations"): + break + +POSSIBLE_LOCATIONS.update([line.strip() for line in door_shuffle_line_gen]) diff --git a/worlds/witness/options.py b/worlds/witness/options.py index e2b35069b066..2447571726c3 100644 --- a/worlds/witness/options.py +++ b/worlds/witness/options.py @@ -17,6 +17,7 @@ from .data import static_items as static_witness_items from .data import static_logic as static_witness_logic +from .data import static_locations as static_witness_locations from .data.item_definition_classes import ItemCategory, WeightedItemDefinition @@ -441,6 +442,8 @@ class AlwaysHintItems(ItemSet): "Progressive Dots", } + valid_keys = static_witness_items.POSSIBLE_ITEMS + class AlwaysHintLocations(LocationSet): """ @@ -457,6 +460,8 @@ class AlwaysHintLocations(LocationSet): "Mountainside Cloud Cycle EP", } + valid_keys = static_witness_locations.POSSIBLE_LOCATIONS + class PriorityHintItems(ItemSet): """ @@ -464,6 +469,8 @@ class PriorityHintItems(ItemSet): """ display_name = "Priority Hint Items" + valid_keys = static_witness_items.POSSIBLE_ITEMS + class PriorityHintLocations(LocationSet): """ @@ -491,6 +498,8 @@ class PriorityHintLocations(LocationSet): "Quarry Stoneworks Control Room Left", } + valid_keys = static_witness_locations.POSSIBLE_LOCATIONS + class PrioritySymbols(Range): """ From 1e06005262eb5e0e2c1449c8bc15b0e257568212 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Mon, 29 Jul 2024 00:15:41 +0200 Subject: [PATCH 04/20] ruff thing --- .run/Archipelago Unittests.run.xml | 3 ++- worlds/witness/data/static_locations.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.run/Archipelago Unittests.run.xml b/.run/Archipelago Unittests.run.xml index 24fea0f73fec..139fdab38c07 100644 --- a/.run/Archipelago Unittests.run.xml +++ b/.run/Archipelago Unittests.run.xml @@ -1,6 +1,7 @@ + diff --git a/worlds/witness/data/static_locations.py b/worlds/witness/data/static_locations.py index b0a3d9b69e95..b1efda47f84a 100644 --- a/worlds/witness/data/static_locations.py +++ b/worlds/witness/data/static_locations.py @@ -1,6 +1,7 @@ -from typing import Dict, Set, cast, List +from typing import Dict, List, Set, cast -from . import static_logic as static_witness_logic, utils +from . import static_logic as static_witness_logic +from . import utils ID_START = 158000 From 0da84b0e5e7fe24382983cd45c65cf7feed9d4c0 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Tue, 20 Aug 2024 11:58:23 +0200 Subject: [PATCH 05/20] gotta stop doing this --- .run/Archipelago Unittests.run.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.run/Archipelago Unittests.run.xml b/.run/Archipelago Unittests.run.xml index 139fdab38c07..24fea0f73fec 100644 --- a/.run/Archipelago Unittests.run.xml +++ b/.run/Archipelago Unittests.run.xml @@ -1,7 +1,6 @@ - From ed1553af579450194a4d04da92d6c55185b67fef Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Tue, 20 Aug 2024 12:00:15 +0200 Subject: [PATCH 06/20] ruff --- worlds/witness/options.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/witness/options.py b/worlds/witness/options.py index 2447571726c3..70df6cd0751f 100644 --- a/worlds/witness/options.py +++ b/worlds/witness/options.py @@ -16,8 +16,8 @@ ) from .data import static_items as static_witness_items -from .data import static_logic as static_witness_logic from .data import static_locations as static_witness_locations +from .data import static_logic as static_witness_logic from .data.item_definition_classes import ItemCategory, WeightedItemDefinition From 65a3c22426bbee240f7a8354386a2e5daf56cc04 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sat, 24 Aug 2024 10:08:27 +0200 Subject: [PATCH 07/20] ruff --- worlds/witness/hints.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/worlds/witness/hints.py b/worlds/witness/hints.py index 34c07c43b136..085384540ce6 100644 --- a/worlds/witness/hints.py +++ b/worlds/witness/hints.py @@ -681,8 +681,7 @@ def get_compact_hint_args(hint: WitnessWordedHint, local_player_number: int) -> if hint.vague_location_hint and location.player == local_player_number: assert hint.area is not None # A local vague location hint should have an area argument return location.address, "containing_area:" + hint.area - else: - return location.address, location.player # Scouting does not matter for other players (currently) + return location.address, location.player # Scouting does not matter for other players (currently) # Is junk / undefined hint return -1, local_player_number From 2edc77b3aea0d6f95797b5a75ef0cf56020b16d0 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sat, 24 Aug 2024 10:12:27 +0200 Subject: [PATCH 08/20] Make sure we're only priority hinting actually existing symbols (and technically lasers) as to not waste a priority symbol slot on Arrows --- worlds/witness/hints.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/worlds/witness/hints.py b/worlds/witness/hints.py index 085384540ce6..297913d59f37 100644 --- a/worlds/witness/hints.py +++ b/worlds/witness/hints.py @@ -88,6 +88,8 @@ def get_priority_hint_items(world: "WitnessWorld") -> List[str]: discards = world.options.shuffle_discarded_panels wincon = world.options.victory_condition + existing_items_lookup = {item.name for item in world.own_itempool} + if discards and world.options.discard_symbol_hint == "priority_hint": if difficulty == "sigma_expert": priority.add("Arrows") @@ -109,14 +111,14 @@ def get_priority_hint_items(world: "WitnessWorld") -> List[str]: needed_symbols = world.options.priority_symbols - number_of_symbols needed_lasers = world.options.priority_lasers - number_of_lasers - possible_symbols = sorted(world.item_name_groups["Symbols"] - priority) - possible_lasers = sorted(world.item_name_groups["Lasers"] - priority) + possible_symbols = sorted(world.item_name_groups["Symbols"] & existing_items_lookup - priority) + possible_lasers = sorted(world.item_name_groups["Lasers"] & existing_items_lookup - priority) if needed_symbols > 0: - priority.update(world.random.sample(possible_symbols, needed_symbols)) + priority.update(world.random.sample(possible_symbols, min(len(possible_symbols), needed_symbols))) if needed_lasers > 0: - priority.update(world.random.sample(possible_lasers, needed_lasers)) + priority.update(world.random.sample(possible_lasers, min(len(possible_lasers), needed_lasers))) return sorted(priority) From 148bf9940312feadffa456d7f1c80a6e46f4c133 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sat, 24 Aug 2024 10:14:36 +0200 Subject: [PATCH 09/20] Make sure we're actually testing hints --- worlds/witness/test/test_roll_other_options.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worlds/witness/test/test_roll_other_options.py b/worlds/witness/test/test_roll_other_options.py index bea278a04287..4ec1e7dd6f95 100644 --- a/worlds/witness/test/test_roll_other_options.py +++ b/worlds/witness/test/test_roll_other_options.py @@ -39,6 +39,9 @@ class TestMiscOptions(WitnessTestBase): "vague_hints": "experimental", } + def test_hints(self): + self.world.fill_slot_data() + class TestMaxEntityShuffle(WitnessTestBase): options = { From cd87291e016afc5e6406b640d6632cef4a9e9b91 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sat, 24 Aug 2024 10:15:00 +0200 Subject: [PATCH 10/20] Not only area hints --- worlds/witness/test/test_roll_other_options.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/witness/test/test_roll_other_options.py b/worlds/witness/test/test_roll_other_options.py index 4ec1e7dd6f95..39278894c974 100644 --- a/worlds/witness/test/test_roll_other_options.py +++ b/worlds/witness/test/test_roll_other_options.py @@ -35,7 +35,7 @@ class TestMiscOptions(WitnessTestBase): "death_link_amnesty": 3, "laser_hints": True, "hint_amount": 40, - "area_hint_percentage": 100, + "area_hint_percentage": 75, "vague_hints": "experimental", } From 16027c3d6382a79e817decab1336af8c39eceab8 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sat, 24 Aug 2024 10:17:53 +0200 Subject: [PATCH 11/20] oop --- worlds/witness/test/test_roll_other_options.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/worlds/witness/test/test_roll_other_options.py b/worlds/witness/test/test_roll_other_options.py index 39278894c974..9a1f6aafe0bc 100644 --- a/worlds/witness/test/test_roll_other_options.py +++ b/worlds/witness/test/test_roll_other_options.py @@ -1,3 +1,5 @@ +from Fill import distribute_items_restrictive + from ..test import WitnessTestBase # These are just some random options combinations, just to catch whether I broke anything obvious @@ -39,7 +41,10 @@ class TestMiscOptions(WitnessTestBase): "vague_hints": "experimental", } + run_default_tests = False + def test_hints(self): + distribute_items_restrictive(self.multiworld) self.world.fill_slot_data() From 08c0b790f0e1465f7cd2682f2986d2e3be54ca16 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sat, 24 Aug 2024 13:35:35 +0200 Subject: [PATCH 12/20] We do a little logging. Or like. A lot actually --- worlds/witness/hints.py | 115 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 8 deletions(-) diff --git a/worlds/witness/hints.py b/worlds/witness/hints.py index 297913d59f37..19926ac4cef6 100644 --- a/worlds/witness/hints.py +++ b/worlds/witness/hints.py @@ -142,10 +142,11 @@ def get_priority_hint_locations(world: "WitnessWorld") -> List[str]: def try_getting_location_group_for_location(world: "WitnessWorld", hint_loc: Location) -> Tuple[str, str]: allow_regions = world.options.vague_hints == "experimental" + containing_world = world.multiworld.worlds[hint_loc.player] possible_location_groups = { group_name: group_locations - for group_name, group_locations in world.multiworld.worlds[hint_loc.player].location_name_groups.items() + for group_name, group_locations in containing_world.location_name_groups.items() if hint_loc.name in group_locations } @@ -174,14 +175,25 @@ def try_getting_location_group_for_location(world: "WitnessWorld", hint_loc: Loc for location_group, x in valid_location_groups.items() } + logging.debug( + f"Player {world.player_name}: Eligible location groups for location " + f'"{hint_loc}" ({containing_world.game}): {location_groups_with_weights}.' + ) + location_groups = list(location_groups_with_weights.keys()) weights = list(location_groups_with_weights.values()) return world.random.choices(location_groups, weights, k=1)[0], "Group" + logging.debug( + f"Player {world.player_name}: " + f"Couldn't find suitable location group for location \"{hint_loc}\" ({containing_world.game})." + ) if allow_regions: + logging.debug(f'Falling back on parent region "{hint_loc.parent_region}".') return cast(Region, hint_loc.parent_region).name, "Region" + logging.debug('Falling back on hinting the "Everywhere" group.') return "Everywhere", "Everywhere" @@ -205,6 +217,11 @@ def word_direct_hint(world: "WitnessWorld", hint: WitnessLocationHint) -> Witnes if world.options.vague_hints: chosen_group, group_type = try_getting_location_group_for_location(world, hint.location) + logging.debug( + f"Player {world.player_name}: Vague hints: " + f'Chose group "{chosen_group}" of type "{group_type}" for location "{hint.location}".' + ) + if hint.location.player == world.player: area = chosen_group @@ -313,6 +330,11 @@ def make_always_and_priority_hints(world: "WitnessWorld", own_itempool: List["Wi if location in loc_in_this_world ] + logging.debug(f'Player "{world.player_name}": Always item hints: {always_items}') + logging.debug(f'Player "{world.player_name}": Always location hints: {always_locations}') + logging.debug(f'Player "{world.player_name}": Priority item hints: {priority_items}') + logging.debug(f'Player "{world.player_name}": Priority location hints: {priority_locations}') + # Get always and priority location/item hints always_location_hints = {hint_from_location(world, location) for location in always_locations} always_item_hints = {hint_from_item(world, item, own_itempool) for item in always_items} @@ -335,6 +357,15 @@ def make_always_and_priority_hints(world: "WitnessWorld", own_itempool: List["Wi world.random.shuffle(always_hints) world.random.shuffle(priority_hints) + logging.debug( + f'Player "{world.player_name}": Finalized always hints: ' + f"{[f'{hint.location.item} on {hint.location}' for hint in always_hints]}" + ) + logging.debug( + f'Player "{world.player_name}": Finalized priority hint candidates: ' + f"{[f'{hint.location.item} on {hint.location}' for hint in priority_hints]}" + ) + return always_hints, priority_hints @@ -389,6 +420,11 @@ def make_extra_location_hints(world: "WitnessWorld", hint_amount: int, own_itemp next_random_hint_is_location = not next_random_hint_is_location + logging.debug( + f'Player "{world.player_name}": Remaining hints: ' + f"{[f'{hint.location.item} on {hint.location}' for hint in hints]}" + ) + return hints @@ -414,10 +450,14 @@ def choose_areas(world: "WitnessWorld", amount: int, locations_per_area: Dict[st areas = sorted(area for area in items_per_area if unhinted_location_percentage_per_area[area]) weights = [unhinted_location_percentage_per_area[area] for area in areas] + logging.debug(f'Player "{world.player_name}": Area weights: {unhinted_location_percentage_per_area}') + amount = min(amount, len(weights)) hinted_areas = weighted_sample(world.random, areas, weights, amount) + logging.debug(f'Player "{world.player_name}": Chosen area hints ({len(hinted_areas)}): {hinted_areas}') + return hinted_areas, unhinted_locations_per_area @@ -540,6 +580,8 @@ def word_area_hint(world: "WitnessWorld", hinted_area: str, area_items: List[Ite elif local_lasers: hint_string += f"\n{local_lasers} of them are lasers." + logging.debug(f'Player "{world.player_name}": Wording area hint for {hinted_area} as: "{hint_string}"') + return hint_string, total_progression, hunt_panels @@ -565,6 +607,10 @@ def make_area_hints(world: "WitnessWorld", amount: int, already_hinted_locations def create_all_hints(world: "WitnessWorld", hint_amount: int, area_hints: int, already_hinted_locations: Set[Location]) -> List[WitnessWordedHint]: + start_line = f"Witness hints: {world.player_name} start" + dashes = "-" * len(start_line) + logging.debug(f"{dashes}\n{start_line}\n{dashes}") + generated_hints: List[WitnessWordedHint] = [] state = CollectionState(world.multiworld) @@ -592,10 +638,23 @@ def create_all_hints(world: "WitnessWorld", hint_amount: int, area_hints: int, # Make up to half of the rest of the location hints priority hints, using up to half of the possibly priority hints remaining_location_hints = intended_location_hints - always_hints_to_use - priority_hints_to_use = int(max(0.0, min( - possible_priority_hints * world.options.priority_hints_percentage_out_of_possible / 100, - remaining_location_hints * world.options.priority_hints_percentage_out_of_remaining / 100, - ))) + + priority_cap_possible = possible_priority_hints * world.options.priority_hints_percentage_out_of_possible / 100 + priority_cap_remain = remaining_location_hints * world.options.priority_hints_percentage_out_of_remaining / 100 + + priority_hints_to_use = int(max(0.0, min(priority_cap_possible, priority_cap_remain))) + + amount_of_priority_hint_candidates = len(priority_hints) + + logging.debug( + f'Player "{world.player_name}": ' + f"Using {priority_hints_to_use} priority out of {amount_of_priority_hint_candidates} candidates. " + f"This is the floor of the lower number out of\n" + f"1. {world.options.priority_hints_percentage_out_of_possible}% of {possible_priority_hints} " + f"possible priority hints, which is {priority_cap_possible}.\n" + f"2. {world.options.priority_hints_percentage_out_of_remaining}% of {remaining_location_hints} " + f"remaining hint slots after area and always hints, which is {priority_cap_remain}." + ) for _ in range(always_hints_to_use): location_hint = always_hints.pop() @@ -628,19 +687,55 @@ def create_all_hints(world: "WitnessWorld", hint_amount: int, area_hints: int, intended_location_hints = remaining_needed_location_hints + location_hints_created_in_round_1 always_hints_to_use = min(intended_location_hints, generated_always_hints) - priority_hints_to_use = int(max(0.0, min(possible_priority_hints / 2, remaining_location_hints / 2))) + remaining_location_hints = intended_location_hints - always_hints_to_use + + priority_cap_possible = possible_priority_hints * world.options.priority_hints_percentage_out_of_possible / 100 + priority_cap_remain = remaining_location_hints * world.options.priority_hints_percentage_out_of_remaining / 100 + + priority_hints_to_use = int(max(0.0, min(priority_cap_possible, priority_cap_remain))) # If we now need more always hints and priority hints than we thought previously, make some more. more_always_hints = always_hints_to_use - amt_of_used_always_hints more_priority_hints = priority_hints_to_use - amt_of_used_priority_hints + if more_always_hints or more_priority_hints: + logging.debug( + f'Player "{world.player_name}": ' + f"Reusing always and priority hints as fallback after not enough area hints could be made. " + f"There are {remaining_needed_location_hints} more hints to make now." + ) + + logging.debug( + f'Player "{world.player_name}": ' + f"Now, we will actually use {priority_hints_to_use} out of {amount_of_priority_hint_candidates} " + f"priority candidates. This is the floor of the lower number out of\n" + f"1. {world.options.priority_hints_percentage_out_of_possible}% of {possible_priority_hints} " + f"possible priority hints, which is {priority_cap_possible}.\n" + f"2. {world.options.priority_hints_percentage_out_of_remaining}% of {remaining_location_hints} " + f"remaining hint slots after area and always hints, which is {priority_cap_remain}." + ) + extra_always_and_priority_hints: List[WitnessLocationHint] = [] for _ in range(more_always_hints): - extra_always_and_priority_hints.append(always_hints.pop()) + extra_always_hint = always_hints.pop() + + logging.debug( + f'Player "{world.player_name}": Adding late always hint: ' + f"{extra_always_hint.location.item} on {extra_always_hint.location}" + ) + + extra_always_and_priority_hints.append(extra_always_hint) for _ in range(more_priority_hints): - extra_always_and_priority_hints.append(priority_hints.pop()) + extra_priority_hint = priority_hints.pop() + + logging.debug( + f'Player "{world.player_name}": Adding late priority hint: ' + f"{extra_priority_hint.location.item} on {extra_priority_hint.location}" + ) + + extra_always_and_priority_hints.append(extra_priority_hint) generated_hints += make_extra_location_hints( world, hint_amount - len(generated_hints), world.own_itempool, already_hinted_locations, @@ -652,6 +747,10 @@ def create_all_hints(world: "WitnessWorld", hint_amount: int, area_hints: int, logging.warning(f"Couldn't generate {hint_amount} hints for player {world.player_name}. " f"Generated {len(generated_hints)} instead.") + end_line = f"Witness hints: {world.player_name} end" + dashes = "-" * len(end_line) + logging.debug(f"{dashes}\n{end_line}\n{dashes}") + return generated_hints From fb8f251c9b20ef5b89f003daa2cfe1aff8f44bd3 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sat, 24 Aug 2024 13:37:36 +0200 Subject: [PATCH 13/20] logging 2 --- worlds/witness/hints.py | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/worlds/witness/hints.py b/worlds/witness/hints.py index 19926ac4cef6..ab6c32e6c20d 100644 --- a/worlds/witness/hints.py +++ b/worlds/witness/hints.py @@ -330,10 +330,10 @@ def make_always_and_priority_hints(world: "WitnessWorld", own_itempool: List["Wi if location in loc_in_this_world ] - logging.debug(f'Player "{world.player_name}": Always item hints: {always_items}') - logging.debug(f'Player "{world.player_name}": Always location hints: {always_locations}') - logging.debug(f'Player "{world.player_name}": Priority item hints: {priority_items}') - logging.debug(f'Player "{world.player_name}": Priority location hints: {priority_locations}') + logging.debug(f"Always item hints: {always_items}") + logging.debug(f"Always location hints: {always_locations}") + logging.debug(f"Priority item hints: {priority_items}") + logging.debug(f"Priority location hints: {priority_locations}") # Get always and priority location/item hints always_location_hints = {hint_from_location(world, location) for location in always_locations} @@ -358,11 +358,11 @@ def make_always_and_priority_hints(world: "WitnessWorld", own_itempool: List["Wi world.random.shuffle(priority_hints) logging.debug( - f'Player "{world.player_name}": Finalized always hints: ' + f"Finalized always hints: " f"{[f'{hint.location.item} on {hint.location}' for hint in always_hints]}" ) logging.debug( - f'Player "{world.player_name}": Finalized priority hint candidates: ' + f"Finalized priority hint candidates: " f"{[f'{hint.location.item} on {hint.location}' for hint in priority_hints]}" ) @@ -421,7 +421,7 @@ def make_extra_location_hints(world: "WitnessWorld", hint_amount: int, own_itemp next_random_hint_is_location = not next_random_hint_is_location logging.debug( - f'Player "{world.player_name}": Remaining hints: ' + f"Remaining hints: " f"{[f'{hint.location.item} on {hint.location}' for hint in hints]}" ) @@ -450,13 +450,13 @@ def choose_areas(world: "WitnessWorld", amount: int, locations_per_area: Dict[st areas = sorted(area for area in items_per_area if unhinted_location_percentage_per_area[area]) weights = [unhinted_location_percentage_per_area[area] for area in areas] - logging.debug(f'Player "{world.player_name}": Area weights: {unhinted_location_percentage_per_area}') + logging.debug(f"Area weights: {unhinted_location_percentage_per_area}") amount = min(amount, len(weights)) hinted_areas = weighted_sample(world.random, areas, weights, amount) - logging.debug(f'Player "{world.player_name}": Chosen area hints ({len(hinted_areas)}): {hinted_areas}') + logging.debug(f"Chosen area hints ({len(hinted_areas)}): {hinted_areas}") return hinted_areas, unhinted_locations_per_area @@ -580,7 +580,7 @@ def word_area_hint(world: "WitnessWorld", hinted_area: str, area_items: List[Ite elif local_lasers: hint_string += f"\n{local_lasers} of them are lasers." - logging.debug(f'Player "{world.player_name}": Wording area hint for {hinted_area} as: "{hint_string}"') + logging.debug(f'Wording area hint for {hinted_area} as: "{hint_string}"') return hint_string, total_progression, hunt_panels @@ -647,7 +647,6 @@ def create_all_hints(world: "WitnessWorld", hint_amount: int, area_hints: int, amount_of_priority_hint_candidates = len(priority_hints) logging.debug( - f'Player "{world.player_name}": ' f"Using {priority_hints_to_use} priority out of {amount_of_priority_hint_candidates} candidates. " f"This is the floor of the lower number out of\n" f"1. {world.options.priority_hints_percentage_out_of_possible}% of {possible_priority_hints} " @@ -700,13 +699,11 @@ def create_all_hints(world: "WitnessWorld", hint_amount: int, area_hints: int, if more_always_hints or more_priority_hints: logging.debug( - f'Player "{world.player_name}": ' f"Reusing always and priority hints as fallback after not enough area hints could be made. " f"There are {remaining_needed_location_hints} more hints to make now." ) logging.debug( - f'Player "{world.player_name}": ' f"Now, we will actually use {priority_hints_to_use} out of {amount_of_priority_hint_candidates} " f"priority candidates. This is the floor of the lower number out of\n" f"1. {world.options.priority_hints_percentage_out_of_possible}% of {possible_priority_hints} " @@ -721,7 +718,7 @@ def create_all_hints(world: "WitnessWorld", hint_amount: int, area_hints: int, extra_always_hint = always_hints.pop() logging.debug( - f'Player "{world.player_name}": Adding late always hint: ' + f"Adding late always hint: " f"{extra_always_hint.location.item} on {extra_always_hint.location}" ) @@ -731,7 +728,7 @@ def create_all_hints(world: "WitnessWorld", hint_amount: int, area_hints: int, extra_priority_hint = priority_hints.pop() logging.debug( - f'Player "{world.player_name}": Adding late priority hint: ' + f"Adding late priority hint: " f"{extra_priority_hint.location.item} on {extra_priority_hint.location}" ) From 8ddc3f29179bfde4c6ba98e6de2442898b4e6415 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sat, 24 Aug 2024 13:43:07 +0200 Subject: [PATCH 14/20] logging 3 --- worlds/witness/hints.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/worlds/witness/hints.py b/worlds/witness/hints.py index ab6c32e6c20d..0d2654f765be 100644 --- a/worlds/witness/hints.py +++ b/worlds/witness/hints.py @@ -318,8 +318,13 @@ def make_always_and_priority_hints(world: "WitnessWorld", own_itempool: List["Wi if item in prog_items_in_this_world ] + logging.debug(f"Always item hints: {always_items}") + logging.debug(f"Priority item hints: {priority_items}") + if world.options.vague_hints: always_locations, priority_locations = [], [] + + logging.debug("No always / priority location hints because this world wants vague hints.") else: always_locations = [ location for location in get_always_hint_locations(world) @@ -330,10 +335,8 @@ def make_always_and_priority_hints(world: "WitnessWorld", own_itempool: List["Wi if location in loc_in_this_world ] - logging.debug(f"Always item hints: {always_items}") - logging.debug(f"Always location hints: {always_locations}") - logging.debug(f"Priority item hints: {priority_items}") - logging.debug(f"Priority location hints: {priority_locations}") + logging.debug(f"Always location hints: {always_locations}") + logging.debug(f"Priority location hints: {priority_locations}") # Get always and priority location/item hints always_location_hints = {hint_from_location(world, location) for location in always_locations} From e85447948c4f2e649a9fab53d5a0d1ea1ee16500 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sat, 24 Aug 2024 13:45:17 +0200 Subject: [PATCH 15/20] logging 4 --- worlds/witness/hints.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/worlds/witness/hints.py b/worlds/witness/hints.py index 0d2654f765be..6f41f65a8d9c 100644 --- a/worlds/witness/hints.py +++ b/worlds/witness/hints.py @@ -176,7 +176,7 @@ def try_getting_location_group_for_location(world: "WitnessWorld", hint_loc: Loc } logging.debug( - f"Player {world.player_name}: Eligible location groups for location " + f"Eligible location groups for location " f'"{hint_loc}" ({containing_world.game}): {location_groups_with_weights}.' ) @@ -186,7 +186,6 @@ def try_getting_location_group_for_location(world: "WitnessWorld", hint_loc: Loc return world.random.choices(location_groups, weights, k=1)[0], "Group" logging.debug( - f"Player {world.player_name}: " f"Couldn't find suitable location group for location \"{hint_loc}\" ({containing_world.game})." ) if allow_regions: From 88c2881ff71a203b6da286f7eea65047b0a77a88 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sat, 24 Aug 2024 13:46:09 +0200 Subject: [PATCH 16/20] logging 5 --- worlds/witness/hints.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/worlds/witness/hints.py b/worlds/witness/hints.py index 6f41f65a8d9c..228756078881 100644 --- a/worlds/witness/hints.py +++ b/worlds/witness/hints.py @@ -217,8 +217,7 @@ def word_direct_hint(world: "WitnessWorld", hint: WitnessLocationHint) -> Witnes chosen_group, group_type = try_getting_location_group_for_location(world, hint.location) logging.debug( - f"Player {world.player_name}: Vague hints: " - f'Chose group "{chosen_group}" of type "{group_type}" for location "{hint.location}".' + f'Vague hints: Chose group "{chosen_group}" of type "{group_type}" for location "{hint.location}".' ) if hint.location.player == world.player: From 5c4d9cdd6c19bcec83940719522a8abfad173eba Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sun, 3 Nov 2024 21:03:04 +0100 Subject: [PATCH 17/20] Make Black/White Squares always a priority symbol --- worlds/witness/options.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worlds/witness/options.py b/worlds/witness/options.py index 47e6f6c5b62d..dee00c19b486 100644 --- a/worlds/witness/options.py +++ b/worlds/witness/options.py @@ -479,6 +479,9 @@ class PriorityHintItems(ItemSet): Items that will have increased priority to be hinted if they exist in the itempool. """ display_name = "Priority Hint Items" + default = { + "Black/White Squares", + } valid_keys = static_witness_items.POSSIBLE_ITEMS From 20db413ff52a28b67fb680f0792586e9d544cbce Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Thu, 12 Dec 2024 20:14:45 +0100 Subject: [PATCH 18/20] variety support and slight rewrite --- worlds/witness/hints.py | 26 +++++++++++++------------- worlds/witness/options.py | 5 ++++- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/worlds/witness/hints.py b/worlds/witness/hints.py index 2759d2c8ffa5..bd6cfc00e783 100644 --- a/worlds/witness/hints.py +++ b/worlds/witness/hints.py @@ -42,26 +42,26 @@ class WitnessWordedHint: def get_always_hint_items(world: "WitnessWorld") -> List[str]: - always = sorted(world.options.always_hint_items.value) + always = world.options.always_hint_items.value.copy() difficulty = world.options.puzzle_randomization discards = world.options.shuffle_discarded_panels wincon = world.options.victory_condition if discards and world.options.discard_symbol_hint == "always_hint": - if difficulty == "sigma_expert" or difficulty == "umbra_variety": - always.append("Arrows") - else: - always.append("Triangles") + if difficulty in ("sigma_expert", "umbra_variety"): + always.add("Arrows") + if difficulty in ("none", "sigma_normal", "umbra_variety"): + always.add("Triangles") - if world.options.final_door_hint == "always_hint": + if world.options.final_door_hint == "priority_hint": if wincon == "elevator": - always += ["Mountain Bottom Floor Pillars Room Entry (Door)", "Mountain Bottom Floor Doors"] + always |= {"Mountain Bottom Floor Pillars Room Entry (Door)", "Mountain Bottom Floor Doors"} if wincon == "challenge": - always += ["Challenge Entry (Panel)", "Caves Panels", "Challenge Entry (Door)", "Caves Doors"] + always |= {"Challenge Entry (Panel)", "Caves Panels", "Challenge Entry (Door)", "Caves Doors"} - return always + return sorted(always) def get_always_hint_locations(world: "WitnessWorld") -> List[str]: @@ -82,7 +82,7 @@ def get_always_hint_locations(world: "WitnessWorld") -> List[str]: def get_priority_hint_items(world: "WitnessWorld") -> List[str]: - priority = world.options.priority_hint_items.value + priority = world.options.priority_hint_items.value.copy() difficulty = world.options.puzzle_randomization discards = world.options.shuffle_discarded_panels @@ -90,10 +90,10 @@ def get_priority_hint_items(world: "WitnessWorld") -> List[str]: existing_items_lookup = {item.name for item in world.own_itempool} - if discards and world.options.discard_symbol_hint == "priority_hint": - if difficulty == "sigma_expert": + if discards and world.options.discard_symbol_hint == "always_hint": + if difficulty in ("sigma_expert", "umbra_variety"): priority.add("Arrows") - else: + if difficulty in ("none", "sigma_normal", "umbra_variety"): priority.add("Triangles") if world.options.final_door_hint == "priority_hint": diff --git a/worlds/witness/options.py b/worlds/witness/options.py index 9a439635e1af..c6ff2394cf21 100644 --- a/worlds/witness/options.py +++ b/worlds/witness/options.py @@ -471,7 +471,10 @@ class PuzzleRandomizationSeed(Range): class DiscardSymbolHint(Choice): """ - Controls whether the symbol required to solve Discarded Panels (Triangles / Arrows) has elevated priority for Audio Log hints. + Controls whether the symbol(s) required to solve Discarded Panels have elevated priority for Audio Log hints. + In vanilla and sigma_normal, this is Triangles. + In sigma_expert, this is Arrows. + In umbra_variety, this is both Triangles and Arrows. """ display_name = "Discarded Panel Symbol Hint" From 9f1280adb9494d546f88e3c8921d4a723489c29e Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Thu, 12 Dec 2024 20:21:03 +0100 Subject: [PATCH 19/20] ensure that POSSIBLE_LOCATIONS is exhaustive through an assert that will fail unit tests --- worlds/witness/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/worlds/witness/__init__.py b/worlds/witness/__init__.py index 095ada418b63..87b424ad28aa 100644 --- a/worlds/witness/__init__.py +++ b/worlds/witness/__init__.py @@ -14,6 +14,7 @@ from .data import static_locations as static_witness_locations from .data import static_logic as static_witness_logic from .data.item_definition_classes import DoorItemDefinition, ItemData +from .data.static_locations import POSSIBLE_LOCATIONS from .data.utils import cast_not_none, get_audio_logs from .hints import CompactHintData, create_all_hints, make_compact_hint_data, make_laser_hints from .locations import WitnessPlayerLocations @@ -258,6 +259,12 @@ def create_regions(self) -> None: due to insufficient sphere 1 size.""" ) + assert all( + location.name in POSSIBLE_LOCATIONS + for location in self.multiworld.get_locations(self.player) + if not location.is_event + ) + def create_items(self) -> None: # Determine pool size. pool_size = len(self.player_locations.CHECK_LOCATION_TABLE) - len(self.player_locations.EVENT_LOCATION_TABLE) From af61935a4d90833ee5a1089f8ed7936c4995caed Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Thu, 12 Dec 2024 20:22:00 +0100 Subject: [PATCH 20/20] comment --- worlds/witness/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worlds/witness/__init__.py b/worlds/witness/__init__.py index 87b424ad28aa..c485c0b91686 100644 --- a/worlds/witness/__init__.py +++ b/worlds/witness/__init__.py @@ -259,11 +259,12 @@ def create_regions(self) -> None: due to insufficient sphere 1 size.""" ) + # Ensure that POSSIBLE_LOCATIONS is exhaustive by failing on dev if any locations aren't in it assert all( location.name in POSSIBLE_LOCATIONS for location in self.multiworld.get_locations(self.player) if not location.is_event - ) + ), "POSSIBLE_LOCATIONS is not exhaustive." def create_items(self) -> None: # Determine pool size.