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>
This commit is contained in:
@@ -10,7 +10,6 @@ from worlds.generic.Rules import CollectionRule, set_rule
|
||||
|
||||
from .data import static_logic as static_witness_logic
|
||||
from .data.utils import WitnessRule
|
||||
from .locations import WitnessPlayerLocations
|
||||
from .player_logic import WitnessPlayerLogic
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -31,42 +30,37 @@ laser_hexes = [
|
||||
]
|
||||
|
||||
|
||||
def _has_laser(laser_hex: str, world: "WitnessWorld", player: int, redirect_required: bool) -> CollectionRule:
|
||||
if laser_hex == "0x012FB" and redirect_required:
|
||||
return lambda state: (
|
||||
_can_solve_panel(laser_hex, world, world.player, world.player_logic, world.player_locations)(state)
|
||||
and state.has("Desert Laser Redirection", player)
|
||||
)
|
||||
def _can_do_panel_hunt(world: "WitnessWorld") -> CollectionRule:
|
||||
required = world.panel_hunt_required_count
|
||||
player = world.player
|
||||
return lambda state: state.has("+1 Panel Hunt", player, required)
|
||||
|
||||
return _can_solve_panel(laser_hex, world, world.player, world.player_logic, world.player_locations)
|
||||
|
||||
def _has_laser(laser_hex: str, world: "WitnessWorld", redirect_required: bool) -> CollectionRule:
|
||||
player = world.player
|
||||
laser_name = static_witness_logic.ENTITIES_BY_HEX[laser_hex]["checkName"]
|
||||
|
||||
# Workaround for intentional naming inconsistency
|
||||
if laser_name == "Symmetry Island Laser":
|
||||
laser_name = "Symmetry Laser"
|
||||
|
||||
if laser_hex == "0x012FB" and redirect_required:
|
||||
return lambda state: state.has_all([f"+1 Laser ({laser_name})", "Desert Laser Redirection"], player)
|
||||
|
||||
return lambda state: state.has(f"+1 Laser ({laser_name})", player)
|
||||
|
||||
|
||||
def _has_lasers(amount: int, world: "WitnessWorld", redirect_required: bool) -> CollectionRule:
|
||||
laser_lambdas = []
|
||||
|
||||
for laser_hex in laser_hexes:
|
||||
has_laser_lambda = _has_laser(laser_hex, world, world.player, redirect_required)
|
||||
has_laser_lambda = _has_laser(laser_hex, world, redirect_required)
|
||||
|
||||
laser_lambdas.append(has_laser_lambda)
|
||||
|
||||
return lambda state: sum(laser_lambda(state) for laser_lambda in laser_lambdas) >= amount
|
||||
|
||||
|
||||
def _can_solve_panel(panel: str, world: "WitnessWorld", player: int, player_logic: WitnessPlayerLogic,
|
||||
player_locations: WitnessPlayerLocations) -> CollectionRule:
|
||||
"""
|
||||
Determines whether a panel can be solved
|
||||
"""
|
||||
|
||||
panel_obj = player_logic.REFERENCE_LOGIC.ENTITIES_BY_HEX[panel]
|
||||
entity_name = panel_obj["checkName"]
|
||||
|
||||
if entity_name + " Solved" in player_locations.EVENT_LOCATION_TABLE:
|
||||
return lambda state: state.has(player_logic.EVENT_ITEM_PAIRS[entity_name + " Solved"], player)
|
||||
|
||||
return make_lambda(panel, world)
|
||||
|
||||
|
||||
def _can_do_expert_pp2(state: CollectionState, world: "WitnessWorld") -> bool:
|
||||
"""
|
||||
For Expert PP2, you need a way to access PP2 from the front, and a separate way from the back.
|
||||
@@ -202,8 +196,9 @@ def _can_do_theater_to_tunnels(state: CollectionState, world: "WitnessWorld") ->
|
||||
)
|
||||
|
||||
|
||||
def _has_item(item: str, world: "WitnessWorld", player: int,
|
||||
player_logic: WitnessPlayerLogic, player_locations: WitnessPlayerLocations) -> CollectionRule:
|
||||
def _has_item(item: str, world: "WitnessWorld", player: int, player_logic: WitnessPlayerLogic) -> CollectionRule:
|
||||
assert item not in static_witness_logic.ENTITIES_BY_HEX, "Requirements can no longer contain entity hexes directly."
|
||||
|
||||
if item in player_logic.REFERENCE_LOGIC.ALL_REGIONS_BY_NAME:
|
||||
region = world.get_region(item)
|
||||
return region.can_reach
|
||||
@@ -219,12 +214,13 @@ def _has_item(item: str, world: "WitnessWorld", player: int,
|
||||
if item == "11 Lasers + Redirect":
|
||||
laser_req = world.options.challenge_lasers.value
|
||||
return _has_lasers(laser_req, world, True)
|
||||
if item == "Entity Hunt":
|
||||
# Right now, panel hunt is the only type of entity hunt. This may need to be changed later
|
||||
return _can_do_panel_hunt(world)
|
||||
if item == "PP2 Weirdness":
|
||||
return lambda state: _can_do_expert_pp2(state, world)
|
||||
if item == "Theater to Tunnels":
|
||||
return lambda state: _can_do_theater_to_tunnels(state, world)
|
||||
if item in player_logic.USED_EVENT_NAMES_BY_HEX:
|
||||
return _can_solve_panel(item, world, player, player_logic, player_locations)
|
||||
|
||||
prog_item = static_witness_logic.get_parent_progressive_item(item)
|
||||
return lambda state: state.has(prog_item, player, player_logic.MULTI_AMOUNTS[item])
|
||||
@@ -237,7 +233,7 @@ def _meets_item_requirements(requirements: WitnessRule, world: "WitnessWorld") -
|
||||
"""
|
||||
|
||||
lambda_conversion = [
|
||||
[_has_item(item, world, world.player, world.player_logic, world.player_locations) for item in subset]
|
||||
[_has_item(item, world, world.player, world.player_logic) for item in subset]
|
||||
for subset in requirements
|
||||
]
|
||||
|
||||
@@ -265,7 +261,8 @@ def set_rules(world: "WitnessWorld") -> None:
|
||||
real_location = location
|
||||
|
||||
if location in world.player_locations.EVENT_LOCATION_TABLE:
|
||||
real_location = location[:-7]
|
||||
entity_hex = world.player_logic.EVENT_ITEM_PAIRS[location][1]
|
||||
real_location = static_witness_logic.ENTITIES_BY_HEX[entity_hex]["checkName"]
|
||||
|
||||
associated_entity = world.player_logic.REFERENCE_LOGIC.ENTITIES_BY_NAME[real_location]
|
||||
entity_hex = associated_entity["entity_hex"]
|
||||
|
||||
Reference in New Issue
Block a user