Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The Witness: Make it so unreachable Audio Logs don't have hints #4558

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
34 changes: 27 additions & 7 deletions worlds/witness/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +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.utils import cast_not_none, get_audio_logs
from .data.utils import cast_not_none
from .hints import CompactHintData, create_all_hints, make_compact_hint_data, make_laser_hints
from .locations import WitnessPlayerLocations
from .options import TheWitnessOptions, witness_option_groups
Expand Down Expand Up @@ -342,26 +342,46 @@ def fill_slot_data(self) -> Dict[str, Any]:
# Audio Log Hints

hint_amount = self.options.hint_amount.value
audio_logs = get_audio_logs().copy()

all_audio_logs = [
entity_hex for entity_hex, entity_obj in static_witness_logic.ENTITIES_BY_HEX.items()
if entity_obj["entityType"] == "Audio Log"
]
enabled_audio_logs = [
log_hex for log_hex in all_audio_logs if log_hex not in self.player_logic.COMPLETELY_DISABLED_ENTITIES
]
disabled_audio_logs = [
log_hex for log_hex in all_audio_logs if log_hex in self.player_logic.COMPLETELY_DISABLED_ENTITIES
]

if hint_amount > len(enabled_audio_logs):
# TODO: Make this an option in the advanced hints PR
warning(
f"Player {self.player_name} requested {hint_amount} hints, but only {enabled_audio_logs} Audio Logs "
f"are available, so only {enabled_audio_logs} hints were created."
)
hint_amount = len(enabled_audio_logs)
self.options.hint_amount.value = hint_amount

if hint_amount:
area_hints = round(self.options.area_hint_percentage / 100 * hint_amount)

generated_hints = create_all_hints(self, hint_amount, area_hints, already_hinted_locations)

self.random.shuffle(audio_logs)
self.random.shuffle(enabled_audio_logs)

duplicates = min(3, len(audio_logs) // hint_amount)
duplicates = min(3, len(enabled_audio_logs) // hint_amount)

for hint in generated_hints:
compact_hint_data = make_compact_hint_data(hint, self.player)

for _ in range(0, duplicates):
audio_log = audio_logs.pop()
audio_log = enabled_audio_logs.pop()
self.log_ids_to_hints[int(audio_log, 16)] = compact_hint_data

# Client will generate joke hints for these.
self.log_ids_to_hints.update({int(audio_log, 16): ("", -1, -1) for audio_log in audio_logs})
# Client will generate joke hints for the remaining unfilled audio logs, including any disabled audio logs.
self.log_ids_to_hints.update({int(audio_log, 16): ("", -1, -1) for audio_log in enabled_audio_logs})
self.log_ids_to_hints.update({int(audio_log, 16): ("", -1, -1) for audio_log in disabled_audio_logs})

# Options for the client & auto-tracker

Expand Down
83 changes: 73 additions & 10 deletions worlds/witness/data/WitnessLogic.txt

Large diffs are not rendered by default.

83 changes: 73 additions & 10 deletions worlds/witness/data/WitnessLogicExpert.txt

Large diffs are not rendered by default.

83 changes: 73 additions & 10 deletions worlds/witness/data/WitnessLogicVanilla.txt

Large diffs are not rendered by default.

83 changes: 73 additions & 10 deletions worlds/witness/data/WitnessLogicVariety.txt

Large diffs are not rendered by default.

49 changes: 0 additions & 49 deletions worlds/witness/data/settings/Audio_Logs.txt

This file was deleted.

7 changes: 5 additions & 2 deletions worlds/witness/data/static_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def read_logic_file(self, lines: List[str]) -> None:

full_entity_name = current_region["shortName"] + " " + entity_name

if location_id == "Door" or location_id == "Laser":
if location_id in ("Door", "Laser", "Audio Log"):
self.ENTITIES_BY_HEX[entity_hex] = {
"checkName": full_entity_name,
"entity_hex": entity_hex,
Expand Down Expand Up @@ -131,7 +131,10 @@ def read_logic_file(self, lines: List[str]) -> None:
"Laser Pressure Plates",
}

if "Discard" in entity_name:
if location_id == "Audio Log":
entity_type = "Audio Log"
location_type = None
elif "Discard" in entity_name:
entity_type = "Panel"
location_type = "Discard"
elif "Vault" in entity_name:
Expand Down
4 changes: 0 additions & 4 deletions worlds/witness/data/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,6 @@ def get_laser_shuffle() -> List[str]:
return get_adjustment_file("settings/Laser_Shuffle.txt")


def get_audio_logs() -> List[str]:
return get_adjustment_file("settings/Audio_Logs.txt")


def get_ep_all_individual() -> List[str]:
return get_adjustment_file("settings/EP_Shuffle/EP_All.txt")

Expand Down
3 changes: 3 additions & 0 deletions worlds/witness/player_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,9 @@ def make_options_adjustments(self, world: "WitnessWorld") -> None:
if loc_obj["entityType"] == "EP":
self.COMPLETELY_DISABLED_ENTITIES.add(loc_obj["entity_hex"])

elif loc_obj["entityType"] == "Audio Log":
self.COMPLETELY_DISABLED_ENTITIES.add(loc_obj["entity_hex"])

elif loc_obj["entityType"] == "Panel":
self.EXCLUDED_ENTITIES.add(loc_obj["entity_hex"])

Expand Down
85 changes: 85 additions & 0 deletions worlds/witness/test/test_audio_log_hints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from typing import cast

from Fill import distribute_items_restrictive

from worlds.AutoWorld import call_all
from worlds.witness import WitnessWorld
from worlds.witness.test import WitnessMultiworldTestBase


class TestDisabledAudioLogs(WitnessMultiworldTestBase):
options_per_world = [
{
"shuffle_postgame": False,
"disable_non_randomized_puzzles": False,
},
{
"shuffle_postgame": False,
"disable_non_randomized_puzzles": True,
},
{
"shuffle_postgame": True,
"disable_non_randomized_puzzles": False,
},
{
"shuffle_postgame": True,
"disable_non_randomized_puzzles": True,
},
]

common_options = {
"victory_condition": "mountain_box_short",
"shuffle_doors": "off",
"hint_amount": 49,
}

def setUp(self) -> None:
super().setUp()
distribute_items_restrictive(self.multiworld)
call_all(self.multiworld, "fill_slot_data")

def test_disabled_audio_logs(self) -> None:
worlds = [cast(WitnessWorld, world) for world in self.multiworld.worlds.values()]

with self.subTest(
"Check that shuffle_postgame and disable_non_randomized disable the correct amount of Audio Logs and that "
'the "hint_amount" option was appropriately adjusted'
):
for player, expected_audio_log_amount in zip([0, 1, 2, 3], [36, 32, 49, 45]):
self.assertEqual(worlds[player].options.hint_amount, expected_audio_log_amount)

town_obelisk_audio_log = 0x015B7
monastery_audio_log = 0x3C106
tunnels_audio_log = 0x3C105

with self.subTest(
"Check that disabled Audio Logs had junk hints put on them, and vice versa.",
options=self.options_per_world[0]
):
self.assertTrue(worlds[0].log_ids_to_hints[town_obelisk_audio_log][0])
self.assertTrue(worlds[0].log_ids_to_hints[monastery_audio_log][0])
self.assertFalse(worlds[0].log_ids_to_hints[tunnels_audio_log][0])

with self.subTest(
"Check that disabled Audio Logs had junk hints put on them, and vice versa.",
options=self.options_per_world[1]
):
self.assertTrue(worlds[1].log_ids_to_hints[town_obelisk_audio_log][0])
self.assertFalse(worlds[1].log_ids_to_hints[monastery_audio_log][0])
self.assertFalse(worlds[1].log_ids_to_hints[tunnels_audio_log][0])

with self.subTest(
"Check that disabled Audio Logs had junk hints put on them, and vice versa.",
options=self.options_per_world[2]
):
self.assertTrue(worlds[2].log_ids_to_hints[town_obelisk_audio_log][0])
self.assertTrue(worlds[2].log_ids_to_hints[monastery_audio_log][0])
self.assertTrue(worlds[2].log_ids_to_hints[tunnels_audio_log][0])

with self.subTest(
"Check that disabled Audio Logs had junk hints put on them, and vice versa.",
options=self.options_per_world[3]
):
self.assertTrue(worlds[3].log_ids_to_hints[town_obelisk_audio_log][0])
self.assertFalse(worlds[3].log_ids_to_hints[monastery_audio_log][0])
self.assertTrue(worlds[3].log_ids_to_hints[tunnels_audio_log][0])
Loading