Archipelago/worlds/witness/entity_hunt.py

269 lines
12 KiB
Python
Raw Normal View History

The Witness: Panel Hunt Mode (#3265) * Add panel hunt options * Make sure all panels are either solvable or disabled in panel hunt * Pick huntable panels * Discards in disable non randomized * Set up panel hunt requirement * Panel hunt functional * Make it so an event can have multiple names * Panel hunt with events * Add hunt entities to slot data * ruff * add to hint data, no client sneding yet * encode panel hunt amount in compact hint data * Remove print statement * my b * consistent * meh * additions for lcient * Nah * Victory panels ineligible for panel hunt * Panel Hunt Postgame option * cleanup * Add data generation file * pull out set * always disable gate ep in panel hunt * Disallow certain challenge panels from being panel hunt panels * Make panelhuntpostgame its own function, so it can be called even if normal postgame is enabled * disallow PP resets from panel hunt * Disable challenge timer and elevetor start respectively in disable hunt postgame * Fix panelhunt postgame * lol * When you test that the bug is fixed but not that the non-bug is not unfixed * Prevent Obelisks from being panel hunt panels * Make picking panels for panel hunt a bit more sophisticated, if less random * Better function maybe ig * Ok maybe that was a bit too much * Give advanced players some control over panel hunt * lint * correct the logic for amount to pick * decided the jingle thing was dumb, I'll figure sth out client side. Same area discouragement is now a configurable factor, and the logic has been significantly rewritten * comment * Make the option visible * Safety * Change assert slightly * We do a little logging * number tweak & we do a lil logging * we do a little more logging * Ruff * Panel Hunt Option Group * Idk how that got here * Update worlds/witness/options.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update worlds/witness/__init__.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * remove merge error * Update worlds/witness/player_logic.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * True * Don't have underwater sliding bridge when you have above water sliding bridge * These are not actually connected lol * get rid of unnecessary variable * Refactor compact hint function again * lint * Pull out Entity Hunt Picking into its own class, split it into many functions. Kept a lot of the comments tho * forgot to actually add the new file * some more refactoring & docstrings * consistent naming * flip elif change * Comment about naming * Make static eligible panels a constant I can refer back to * slight formatting change * pull out options-based eligibility into its own function * better text and stuff * lint * this is not necessary * capitalisation * Fix same area discouragement 0 * Simplify data file generation * Simplify data file generation * prevent div 0 * Add Vault Boxes -> Vault Panels to replacements * Update options.py * Update worlds/witness/entity_hunt.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update entity_hunt.py * Fix some events not working * assert * remove now unused function * lint * Lasers Activate, Lasers don't Solve * lint * oops * mypy * lint * Add simple panel hunt unit test * Add Panel Hunt Tests * Add more Panel Hunt Tests * Disallow Box Short for normal panel hunt --------- Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-19 23:16:35 +00:00
from collections import defaultdict
from logging import debug, warning
The Witness: Panel Hunt Mode (#3265) * Add panel hunt options * Make sure all panels are either solvable or disabled in panel hunt * Pick huntable panels * Discards in disable non randomized * Set up panel hunt requirement * Panel hunt functional * Make it so an event can have multiple names * Panel hunt with events * Add hunt entities to slot data * ruff * add to hint data, no client sneding yet * encode panel hunt amount in compact hint data * Remove print statement * my b * consistent * meh * additions for lcient * Nah * Victory panels ineligible for panel hunt * Panel Hunt Postgame option * cleanup * Add data generation file * pull out set * always disable gate ep in panel hunt * Disallow certain challenge panels from being panel hunt panels * Make panelhuntpostgame its own function, so it can be called even if normal postgame is enabled * disallow PP resets from panel hunt * Disable challenge timer and elevetor start respectively in disable hunt postgame * Fix panelhunt postgame * lol * When you test that the bug is fixed but not that the non-bug is not unfixed * Prevent Obelisks from being panel hunt panels * Make picking panels for panel hunt a bit more sophisticated, if less random * Better function maybe ig * Ok maybe that was a bit too much * Give advanced players some control over panel hunt * lint * correct the logic for amount to pick * decided the jingle thing was dumb, I'll figure sth out client side. Same area discouragement is now a configurable factor, and the logic has been significantly rewritten * comment * Make the option visible * Safety * Change assert slightly * We do a little logging * number tweak & we do a lil logging * we do a little more logging * Ruff * Panel Hunt Option Group * Idk how that got here * Update worlds/witness/options.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update worlds/witness/__init__.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * remove merge error * Update worlds/witness/player_logic.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * True * Don't have underwater sliding bridge when you have above water sliding bridge * These are not actually connected lol * get rid of unnecessary variable * Refactor compact hint function again * lint * Pull out Entity Hunt Picking into its own class, split it into many functions. Kept a lot of the comments tho * forgot to actually add the new file * some more refactoring & docstrings * consistent naming * flip elif change * Comment about naming * Make static eligible panels a constant I can refer back to * slight formatting change * pull out options-based eligibility into its own function * better text and stuff * lint * this is not necessary * capitalisation * Fix same area discouragement 0 * Simplify data file generation * Simplify data file generation * prevent div 0 * Add Vault Boxes -> Vault Panels to replacements * Update options.py * Update worlds/witness/entity_hunt.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update entity_hunt.py * Fix some events not working * assert * remove now unused function * lint * Lasers Activate, Lasers don't Solve * lint * oops * mypy * lint * Add simple panel hunt unit test * Add Panel Hunt Tests * Add more Panel Hunt Tests * Disallow Box Short for normal panel hunt --------- Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-19 23:16:35 +00:00
from pprint import pformat
from typing import TYPE_CHECKING, Dict, List, Set, Tuple
from .data import static_logic as static_witness_logic
if TYPE_CHECKING:
from . import WitnessWorld
from .player_logic import WitnessPlayerLogic
DISALLOWED_ENTITIES_FOR_PANEL_HUNT = {
"0x03629", # Tutorial Gate Open, which is the panel that is locked by panel hunt
"0x03505", # Tutorial Gate Close (same thing)
"0x3352F", # Gate EP (same thing)
"0x09F7F", # Mountaintop Box Short. This is reserved for panel_hunt_postgame.
"0x00CDB", # Challenge Reallocating
"0x0051F", # Challenge Reallocating
"0x00524", # Challenge Reallocating
"0x00CD4", # Challenge Reallocating
"0x00CB9", # Challenge May Be Unsolvable
"0x00CA1", # Challenge May Be Unsolvable
"0x00C80", # Challenge May Be Unsolvable
"0x00C68", # Challenge May Be Unsolvable
"0x00C59", # Challenge May Be Unsolvable
"0x00C22", # Challenge May Be Unsolvable
"0x0A3A8", # Reset PP
"0x0A3B9", # Reset PP
"0x0A3BB", # Reset PP
"0x0A3AD", # Reset PP
}
ALL_HUNTABLE_PANELS = [
entity_hex
for entity_hex, entity_obj in static_witness_logic.ENTITIES_BY_HEX.items()
if entity_obj["entityType"] == "Panel" and entity_hex not in DISALLOWED_ENTITIES_FOR_PANEL_HUNT
]
class EntityHuntPicker:
def __init__(self, player_logic: "WitnessPlayerLogic", world: "WitnessWorld",
pre_picked_entities: Set[str]) -> None:
self.player_logic = player_logic
self.player_options = world.options
self.player_name = world.player_name
self.random = world.random
self.PRE_PICKED_HUNT_ENTITIES = pre_picked_entities.copy()
self.HUNT_ENTITIES: Set[str] = set()
self._add_plandoed_hunt_panels_to_pre_picked()
The Witness: Panel Hunt Mode (#3265) * Add panel hunt options * Make sure all panels are either solvable or disabled in panel hunt * Pick huntable panels * Discards in disable non randomized * Set up panel hunt requirement * Panel hunt functional * Make it so an event can have multiple names * Panel hunt with events * Add hunt entities to slot data * ruff * add to hint data, no client sneding yet * encode panel hunt amount in compact hint data * Remove print statement * my b * consistent * meh * additions for lcient * Nah * Victory panels ineligible for panel hunt * Panel Hunt Postgame option * cleanup * Add data generation file * pull out set * always disable gate ep in panel hunt * Disallow certain challenge panels from being panel hunt panels * Make panelhuntpostgame its own function, so it can be called even if normal postgame is enabled * disallow PP resets from panel hunt * Disable challenge timer and elevetor start respectively in disable hunt postgame * Fix panelhunt postgame * lol * When you test that the bug is fixed but not that the non-bug is not unfixed * Prevent Obelisks from being panel hunt panels * Make picking panels for panel hunt a bit more sophisticated, if less random * Better function maybe ig * Ok maybe that was a bit too much * Give advanced players some control over panel hunt * lint * correct the logic for amount to pick * decided the jingle thing was dumb, I'll figure sth out client side. Same area discouragement is now a configurable factor, and the logic has been significantly rewritten * comment * Make the option visible * Safety * Change assert slightly * We do a little logging * number tweak & we do a lil logging * we do a little more logging * Ruff * Panel Hunt Option Group * Idk how that got here * Update worlds/witness/options.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update worlds/witness/__init__.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * remove merge error * Update worlds/witness/player_logic.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * True * Don't have underwater sliding bridge when you have above water sliding bridge * These are not actually connected lol * get rid of unnecessary variable * Refactor compact hint function again * lint * Pull out Entity Hunt Picking into its own class, split it into many functions. Kept a lot of the comments tho * forgot to actually add the new file * some more refactoring & docstrings * consistent naming * flip elif change * Comment about naming * Make static eligible panels a constant I can refer back to * slight formatting change * pull out options-based eligibility into its own function * better text and stuff * lint * this is not necessary * capitalisation * Fix same area discouragement 0 * Simplify data file generation * Simplify data file generation * prevent div 0 * Add Vault Boxes -> Vault Panels to replacements * Update options.py * Update worlds/witness/entity_hunt.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update entity_hunt.py * Fix some events not working * assert * remove now unused function * lint * Lasers Activate, Lasers don't Solve * lint * oops * mypy * lint * Add simple panel hunt unit test * Add Panel Hunt Tests * Add more Panel Hunt Tests * Disallow Box Short for normal panel hunt --------- Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-19 23:16:35 +00:00
self.ALL_ELIGIBLE_ENTITIES, self.ELIGIBLE_ENTITIES_PER_AREA = self._get_eligible_panels()
def pick_panel_hunt_panels(self, total_amount: int) -> Set[str]:
"""
The process of picking all hunt entities is:
1. Add pre-defined hunt entities
2. Pick random hunt entities to fill out the rest
3. Replace unfair entities with fair entities
Each of these is its own function.
"""
self.HUNT_ENTITIES = self.PRE_PICKED_HUNT_ENTITIES.copy()
self._pick_all_hunt_entities(total_amount)
self._replace_unfair_hunt_entities_with_good_hunt_entities()
self._log_results()
return self.HUNT_ENTITIES
def _entity_is_eligible(self, panel_hex: str, plando: bool = False) -> bool:
The Witness: Panel Hunt Mode (#3265) * Add panel hunt options * Make sure all panels are either solvable or disabled in panel hunt * Pick huntable panels * Discards in disable non randomized * Set up panel hunt requirement * Panel hunt functional * Make it so an event can have multiple names * Panel hunt with events * Add hunt entities to slot data * ruff * add to hint data, no client sneding yet * encode panel hunt amount in compact hint data * Remove print statement * my b * consistent * meh * additions for lcient * Nah * Victory panels ineligible for panel hunt * Panel Hunt Postgame option * cleanup * Add data generation file * pull out set * always disable gate ep in panel hunt * Disallow certain challenge panels from being panel hunt panels * Make panelhuntpostgame its own function, so it can be called even if normal postgame is enabled * disallow PP resets from panel hunt * Disable challenge timer and elevetor start respectively in disable hunt postgame * Fix panelhunt postgame * lol * When you test that the bug is fixed but not that the non-bug is not unfixed * Prevent Obelisks from being panel hunt panels * Make picking panels for panel hunt a bit more sophisticated, if less random * Better function maybe ig * Ok maybe that was a bit too much * Give advanced players some control over panel hunt * lint * correct the logic for amount to pick * decided the jingle thing was dumb, I'll figure sth out client side. Same area discouragement is now a configurable factor, and the logic has been significantly rewritten * comment * Make the option visible * Safety * Change assert slightly * We do a little logging * number tweak & we do a lil logging * we do a little more logging * Ruff * Panel Hunt Option Group * Idk how that got here * Update worlds/witness/options.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update worlds/witness/__init__.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * remove merge error * Update worlds/witness/player_logic.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * True * Don't have underwater sliding bridge when you have above water sliding bridge * These are not actually connected lol * get rid of unnecessary variable * Refactor compact hint function again * lint * Pull out Entity Hunt Picking into its own class, split it into many functions. Kept a lot of the comments tho * forgot to actually add the new file * some more refactoring & docstrings * consistent naming * flip elif change * Comment about naming * Make static eligible panels a constant I can refer back to * slight formatting change * pull out options-based eligibility into its own function * better text and stuff * lint * this is not necessary * capitalisation * Fix same area discouragement 0 * Simplify data file generation * Simplify data file generation * prevent div 0 * Add Vault Boxes -> Vault Panels to replacements * Update options.py * Update worlds/witness/entity_hunt.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update entity_hunt.py * Fix some events not working * assert * remove now unused function * lint * Lasers Activate, Lasers don't Solve * lint * oops * mypy * lint * Add simple panel hunt unit test * Add Panel Hunt Tests * Add more Panel Hunt Tests * Disallow Box Short for normal panel hunt --------- Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-19 23:16:35 +00:00
"""
Determine whether an entity is eligible for entity hunt based on player options.
"""
panel_obj = static_witness_logic.ENTITIES_BY_HEX[panel_hex]
if not self.player_logic.solvability_guaranteed(panel_hex) or panel_hex in self.player_logic.EXCLUDED_ENTITIES:
if plando:
warning(f"Panel {panel_obj['checkName']} is disabled / excluded and thus not eligible for panel hunt.")
return False
return plando or not (
# Due to an edge case, Discards have to be on in disable_non_randomized even if Discard Shuffle is off.
# However, I don't think they should be hunt panels in this case.
self.player_options.disable_non_randomized_puzzles
and not self.player_options.shuffle_discarded_panels
and panel_obj["locationType"] == "Discard"
The Witness: Panel Hunt Mode (#3265) * Add panel hunt options * Make sure all panels are either solvable or disabled in panel hunt * Pick huntable panels * Discards in disable non randomized * Set up panel hunt requirement * Panel hunt functional * Make it so an event can have multiple names * Panel hunt with events * Add hunt entities to slot data * ruff * add to hint data, no client sneding yet * encode panel hunt amount in compact hint data * Remove print statement * my b * consistent * meh * additions for lcient * Nah * Victory panels ineligible for panel hunt * Panel Hunt Postgame option * cleanup * Add data generation file * pull out set * always disable gate ep in panel hunt * Disallow certain challenge panels from being panel hunt panels * Make panelhuntpostgame its own function, so it can be called even if normal postgame is enabled * disallow PP resets from panel hunt * Disable challenge timer and elevetor start respectively in disable hunt postgame * Fix panelhunt postgame * lol * When you test that the bug is fixed but not that the non-bug is not unfixed * Prevent Obelisks from being panel hunt panels * Make picking panels for panel hunt a bit more sophisticated, if less random * Better function maybe ig * Ok maybe that was a bit too much * Give advanced players some control over panel hunt * lint * correct the logic for amount to pick * decided the jingle thing was dumb, I'll figure sth out client side. Same area discouragement is now a configurable factor, and the logic has been significantly rewritten * comment * Make the option visible * Safety * Change assert slightly * We do a little logging * number tweak & we do a lil logging * we do a little more logging * Ruff * Panel Hunt Option Group * Idk how that got here * Update worlds/witness/options.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update worlds/witness/__init__.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * remove merge error * Update worlds/witness/player_logic.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * True * Don't have underwater sliding bridge when you have above water sliding bridge * These are not actually connected lol * get rid of unnecessary variable * Refactor compact hint function again * lint * Pull out Entity Hunt Picking into its own class, split it into many functions. Kept a lot of the comments tho * forgot to actually add the new file * some more refactoring & docstrings * consistent naming * flip elif change * Comment about naming * Make static eligible panels a constant I can refer back to * slight formatting change * pull out options-based eligibility into its own function * better text and stuff * lint * this is not necessary * capitalisation * Fix same area discouragement 0 * Simplify data file generation * Simplify data file generation * prevent div 0 * Add Vault Boxes -> Vault Panels to replacements * Update options.py * Update worlds/witness/entity_hunt.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update entity_hunt.py * Fix some events not working * assert * remove now unused function * lint * Lasers Activate, Lasers don't Solve * lint * oops * mypy * lint * Add simple panel hunt unit test * Add Panel Hunt Tests * Add more Panel Hunt Tests * Disallow Box Short for normal panel hunt --------- Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-19 23:16:35 +00:00
)
def _add_plandoed_hunt_panels_to_pre_picked(self) -> None:
"""
Add panels the player explicitly specified to be included in panel hunt to the pre picked hunt panels.
Output a warning if a panel could not be added for some reason.
"""
# Plandoed hunt panels should be in random order, but deterministic by seed, so we sort, then shuffle
panels_to_plando = sorted(self.player_options.panel_hunt_plando.value)
self.random.shuffle(panels_to_plando)
for location_name in panels_to_plando:
entity_hex = static_witness_logic.ENTITIES_BY_NAME[location_name]["entity_hex"]
if entity_hex in self.PRE_PICKED_HUNT_ENTITIES:
continue
if self._entity_is_eligible(entity_hex, plando=True):
if len(self.PRE_PICKED_HUNT_ENTITIES) == self.player_options.panel_hunt_total:
warning(
f"Panel {location_name} could not be plandoed as a hunt panel for {self.player_name}'s world, "
f"because it would exceed their panel hunt total."
)
continue
self.PRE_PICKED_HUNT_ENTITIES.add(entity_hex)
The Witness: Panel Hunt Mode (#3265) * Add panel hunt options * Make sure all panels are either solvable or disabled in panel hunt * Pick huntable panels * Discards in disable non randomized * Set up panel hunt requirement * Panel hunt functional * Make it so an event can have multiple names * Panel hunt with events * Add hunt entities to slot data * ruff * add to hint data, no client sneding yet * encode panel hunt amount in compact hint data * Remove print statement * my b * consistent * meh * additions for lcient * Nah * Victory panels ineligible for panel hunt * Panel Hunt Postgame option * cleanup * Add data generation file * pull out set * always disable gate ep in panel hunt * Disallow certain challenge panels from being panel hunt panels * Make panelhuntpostgame its own function, so it can be called even if normal postgame is enabled * disallow PP resets from panel hunt * Disable challenge timer and elevetor start respectively in disable hunt postgame * Fix panelhunt postgame * lol * When you test that the bug is fixed but not that the non-bug is not unfixed * Prevent Obelisks from being panel hunt panels * Make picking panels for panel hunt a bit more sophisticated, if less random * Better function maybe ig * Ok maybe that was a bit too much * Give advanced players some control over panel hunt * lint * correct the logic for amount to pick * decided the jingle thing was dumb, I'll figure sth out client side. Same area discouragement is now a configurable factor, and the logic has been significantly rewritten * comment * Make the option visible * Safety * Change assert slightly * We do a little logging * number tweak & we do a lil logging * we do a little more logging * Ruff * Panel Hunt Option Group * Idk how that got here * Update worlds/witness/options.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update worlds/witness/__init__.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * remove merge error * Update worlds/witness/player_logic.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * True * Don't have underwater sliding bridge when you have above water sliding bridge * These are not actually connected lol * get rid of unnecessary variable * Refactor compact hint function again * lint * Pull out Entity Hunt Picking into its own class, split it into many functions. Kept a lot of the comments tho * forgot to actually add the new file * some more refactoring & docstrings * consistent naming * flip elif change * Comment about naming * Make static eligible panels a constant I can refer back to * slight formatting change * pull out options-based eligibility into its own function * better text and stuff * lint * this is not necessary * capitalisation * Fix same area discouragement 0 * Simplify data file generation * Simplify data file generation * prevent div 0 * Add Vault Boxes -> Vault Panels to replacements * Update options.py * Update worlds/witness/entity_hunt.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update entity_hunt.py * Fix some events not working * assert * remove now unused function * lint * Lasers Activate, Lasers don't Solve * lint * oops * mypy * lint * Add simple panel hunt unit test * Add Panel Hunt Tests * Add more Panel Hunt Tests * Disallow Box Short for normal panel hunt --------- Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-19 23:16:35 +00:00
def _get_eligible_panels(self) -> Tuple[List[str], Dict[str, Set[str]]]:
"""
There are some entities that are not allowed for panel hunt for various technical of gameplay reasons.
Make a list of all the ones that *are* eligible, plus a lookup of eligible panels per area.
"""
all_eligible_panels = [
panel for panel in ALL_HUNTABLE_PANELS
if self._entity_is_eligible(panel)
]
eligible_panels_by_area = defaultdict(set)
for eligible_panel in all_eligible_panels:
associated_area = static_witness_logic.ENTITIES_BY_HEX[eligible_panel]["area"]["name"]
eligible_panels_by_area[associated_area].add(eligible_panel)
return all_eligible_panels, eligible_panels_by_area
def _get_percentage_of_hunt_entities_by_area(self) -> Dict[str, float]:
hunt_entities_picked_so_far_prevent_div_0 = max(len(self.HUNT_ENTITIES), 1)
contributing_percentage_per_area = {}
for area, eligible_entities in self.ELIGIBLE_ENTITIES_PER_AREA.items():
amount_of_already_chosen_entities = len(self.ELIGIBLE_ENTITIES_PER_AREA[area] & self.HUNT_ENTITIES)
current_percentage = amount_of_already_chosen_entities / hunt_entities_picked_so_far_prevent_div_0
contributing_percentage_per_area[area] = current_percentage
return contributing_percentage_per_area
def _get_next_random_batch(self, amount: int, same_area_discouragement: float) -> List[str]:
"""
Pick the next batch of hunt entities.
Areas that already have a lot of hunt entities in them will be discouraged from getting more.
The strength of this effect is controlled by the same_area_discouragement factor from the player's options.
"""
percentage_of_hunt_entities_by_area = self._get_percentage_of_hunt_entities_by_area()
max_percentage = max(percentage_of_hunt_entities_by_area.values())
if max_percentage == 0:
allowance_per_area = {area: 1.0 for area in percentage_of_hunt_entities_by_area}
else:
allowance_per_area = {
area: (max_percentage - current_percentage) / max_percentage
for area, current_percentage in percentage_of_hunt_entities_by_area.items()
}
# use same_area_discouragement as lerp factor
allowance_per_area = {
area: (1.0 - same_area_discouragement) + (weight * same_area_discouragement)
for area, weight in allowance_per_area.items()
}
assert min(allowance_per_area.values()) >= 0, (
f"Somehow, an area had a negative weight when picking hunt entities: {allowance_per_area}"
)
remaining_entities, remaining_entity_weights = [], []
for area, eligible_entities in self.ELIGIBLE_ENTITIES_PER_AREA.items():
for panel in sorted(eligible_entities - self.HUNT_ENTITIES):
The Witness: Panel Hunt Mode (#3265) * Add panel hunt options * Make sure all panels are either solvable or disabled in panel hunt * Pick huntable panels * Discards in disable non randomized * Set up panel hunt requirement * Panel hunt functional * Make it so an event can have multiple names * Panel hunt with events * Add hunt entities to slot data * ruff * add to hint data, no client sneding yet * encode panel hunt amount in compact hint data * Remove print statement * my b * consistent * meh * additions for lcient * Nah * Victory panels ineligible for panel hunt * Panel Hunt Postgame option * cleanup * Add data generation file * pull out set * always disable gate ep in panel hunt * Disallow certain challenge panels from being panel hunt panels * Make panelhuntpostgame its own function, so it can be called even if normal postgame is enabled * disallow PP resets from panel hunt * Disable challenge timer and elevetor start respectively in disable hunt postgame * Fix panelhunt postgame * lol * When you test that the bug is fixed but not that the non-bug is not unfixed * Prevent Obelisks from being panel hunt panels * Make picking panels for panel hunt a bit more sophisticated, if less random * Better function maybe ig * Ok maybe that was a bit too much * Give advanced players some control over panel hunt * lint * correct the logic for amount to pick * decided the jingle thing was dumb, I'll figure sth out client side. Same area discouragement is now a configurable factor, and the logic has been significantly rewritten * comment * Make the option visible * Safety * Change assert slightly * We do a little logging * number tweak & we do a lil logging * we do a little more logging * Ruff * Panel Hunt Option Group * Idk how that got here * Update worlds/witness/options.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update worlds/witness/__init__.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * remove merge error * Update worlds/witness/player_logic.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * True * Don't have underwater sliding bridge when you have above water sliding bridge * These are not actually connected lol * get rid of unnecessary variable * Refactor compact hint function again * lint * Pull out Entity Hunt Picking into its own class, split it into many functions. Kept a lot of the comments tho * forgot to actually add the new file * some more refactoring & docstrings * consistent naming * flip elif change * Comment about naming * Make static eligible panels a constant I can refer back to * slight formatting change * pull out options-based eligibility into its own function * better text and stuff * lint * this is not necessary * capitalisation * Fix same area discouragement 0 * Simplify data file generation * Simplify data file generation * prevent div 0 * Add Vault Boxes -> Vault Panels to replacements * Update options.py * Update worlds/witness/entity_hunt.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update entity_hunt.py * Fix some events not working * assert * remove now unused function * lint * Lasers Activate, Lasers don't Solve * lint * oops * mypy * lint * Add simple panel hunt unit test * Add Panel Hunt Tests * Add more Panel Hunt Tests * Disallow Box Short for normal panel hunt --------- Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-19 23:16:35 +00:00
remaining_entities.append(panel)
remaining_entity_weights.append(allowance_per_area[area])
# I don't think this can ever happen, but let's be safe
if sum(remaining_entity_weights) == 0:
remaining_entity_weights = [1] * len(remaining_entity_weights)
return self.random.choices(remaining_entities, weights=remaining_entity_weights, k=amount)
def _pick_all_hunt_entities(self, total_amount: int) -> None:
"""
The core function of the EntityHuntPicker in which all Hunt Entities are picked,
respecting the player's choices for total amount and same area discouragement.
"""
same_area_discouragement = self.player_options.panel_hunt_discourage_same_area_factor / 100
# If we're using random picking, just choose all the entities now and return
if not same_area_discouragement:
hunt_entities = self.random.sample(
[entity for entity in self.ALL_ELIGIBLE_ENTITIES if entity not in self.HUNT_ENTITIES],
k=total_amount - len(self.HUNT_ENTITIES),
)
self.HUNT_ENTITIES.update(hunt_entities)
return
# If we're discouraging entities from the same area being picked, we have to pick entities one at a time
# For higher total counts, we do them in small batches for performance
batch_size = max(1, total_amount // 20)
while len(self.HUNT_ENTITIES) < total_amount:
actual_amount_to_pick = min(batch_size, total_amount - len(self.HUNT_ENTITIES))
self.HUNT_ENTITIES.update(self._get_next_random_batch(actual_amount_to_pick, same_area_discouragement))
def _replace_unfair_hunt_entities_with_good_hunt_entities(self) -> None:
"""
For connected entities that "solve together", make sure that the one you're guaranteed
to be able to see and interact with first is the one that is chosen, so you don't get "surprise entities".
"""
replacements = {
"0x18488": "0x00609", # Replace Swamp Sliding Bridge Underwater -> Swamp Sliding Bridge Above Water
"0x03676": "0x03678", # Replace Quarry Upper Ramp Control -> Lower Ramp Control
"0x03675": "0x03679", # Replace Quarry Upper Lift Control -> Lower Lift Control
"0x03702": "0x15ADD", # Jungle Vault Box -> Jungle Vault Panel
"0x03542": "0x002A6", # Mountainside Vault Box -> Mountainside Vault Panel
"0x03481": "0x033D4", # Tutorial Vault Box -> Tutorial Vault Panel
"0x0339E": "0x0CC7B", # Desert Vault Box -> Desert Vault Panel
"0x03535": "0x00AFB", # Shipwreck Vault Box -> Shipwreck Vault Panel
}
if self.player_options.shuffle_doors < 2:
replacements.update(
{
"0x334DC": "0x334DB", # In door shuffle, the Shadows Timer Panels are disconnected
"0x17CBC": "0x2700B", # In door shuffle, the Laser Timer Panels are disconnected
}
)
for bad_entitiy, good_entity in replacements.items():
# If the bad entity was picked as a hunt entity ...
if bad_entitiy not in self.HUNT_ENTITIES:
continue
# ... and the good entity was not ...
if good_entity in self.HUNT_ENTITIES or good_entity not in self.ALL_ELIGIBLE_ENTITIES:
continue
# ... and it's not a forced pick that should stay the same ...
if bad_entitiy in self.PRE_PICKED_HUNT_ENTITIES:
continue
The Witness: Panel Hunt Mode (#3265) * Add panel hunt options * Make sure all panels are either solvable or disabled in panel hunt * Pick huntable panels * Discards in disable non randomized * Set up panel hunt requirement * Panel hunt functional * Make it so an event can have multiple names * Panel hunt with events * Add hunt entities to slot data * ruff * add to hint data, no client sneding yet * encode panel hunt amount in compact hint data * Remove print statement * my b * consistent * meh * additions for lcient * Nah * Victory panels ineligible for panel hunt * Panel Hunt Postgame option * cleanup * Add data generation file * pull out set * always disable gate ep in panel hunt * Disallow certain challenge panels from being panel hunt panels * Make panelhuntpostgame its own function, so it can be called even if normal postgame is enabled * disallow PP resets from panel hunt * Disable challenge timer and elevetor start respectively in disable hunt postgame * Fix panelhunt postgame * lol * When you test that the bug is fixed but not that the non-bug is not unfixed * Prevent Obelisks from being panel hunt panels * Make picking panels for panel hunt a bit more sophisticated, if less random * Better function maybe ig * Ok maybe that was a bit too much * Give advanced players some control over panel hunt * lint * correct the logic for amount to pick * decided the jingle thing was dumb, I'll figure sth out client side. Same area discouragement is now a configurable factor, and the logic has been significantly rewritten * comment * Make the option visible * Safety * Change assert slightly * We do a little logging * number tweak & we do a lil logging * we do a little more logging * Ruff * Panel Hunt Option Group * Idk how that got here * Update worlds/witness/options.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update worlds/witness/__init__.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * remove merge error * Update worlds/witness/player_logic.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * True * Don't have underwater sliding bridge when you have above water sliding bridge * These are not actually connected lol * get rid of unnecessary variable * Refactor compact hint function again * lint * Pull out Entity Hunt Picking into its own class, split it into many functions. Kept a lot of the comments tho * forgot to actually add the new file * some more refactoring & docstrings * consistent naming * flip elif change * Comment about naming * Make static eligible panels a constant I can refer back to * slight formatting change * pull out options-based eligibility into its own function * better text and stuff * lint * this is not necessary * capitalisation * Fix same area discouragement 0 * Simplify data file generation * Simplify data file generation * prevent div 0 * Add Vault Boxes -> Vault Panels to replacements * Update options.py * Update worlds/witness/entity_hunt.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update entity_hunt.py * Fix some events not working * assert * remove now unused function * lint * Lasers Activate, Lasers don't Solve * lint * oops * mypy * lint * Add simple panel hunt unit test * Add Panel Hunt Tests * Add more Panel Hunt Tests * Disallow Box Short for normal panel hunt --------- Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
2024-08-19 23:16:35 +00:00
# ... replace the bad entity with the good entity.
self.HUNT_ENTITIES.remove(bad_entitiy)
self.HUNT_ENTITIES.add(good_entity)
def _log_results(self) -> None:
final_percentage_by_area = self._get_percentage_of_hunt_entities_by_area()
sorted_area_percentages_dict = dict(sorted(final_percentage_by_area.items(), key=lambda x: x[1]))
sorted_area_percentages_dict_pretty_print = {
area: str(percentage) + (" (maxed)" if self.ELIGIBLE_ENTITIES_PER_AREA[area] <= self.HUNT_ENTITIES else "")
for area, percentage in sorted_area_percentages_dict.items()
}
player_name = self.player_name
discouragemenet_factor = self.player_options.panel_hunt_discourage_same_area_factor
debug(
f'Final area percentages for player "{player_name}" ({discouragemenet_factor} discouragement):\n'
f"{pformat(sorted_area_percentages_dict_pretty_print)}"
)