forked from mirror/Archipelago
Some checks failed
Analyze modified files / flake8 (push) Failing after 2m28s
Build / build-win (push) Has been cancelled
Build / build-ubuntu2204 (push) Has been cancelled
ctest / Test C++ ubuntu-latest (push) Has been cancelled
ctest / Test C++ windows-latest (push) Has been cancelled
Analyze modified files / mypy (push) Has been cancelled
Build and Publish Docker Images / Push Docker image to Docker Hub (push) Successful in 5m4s
Native Code Static Analysis / scan-build (push) Failing after 5m2s
type check / pyright (push) Successful in 1m7s
unittests / Test Python 3.11.2 ubuntu-latest (push) Failing after 16m23s
unittests / Test Python 3.12 ubuntu-latest (push) Failing after 28m19s
unittests / Test Python 3.13 ubuntu-latest (push) Failing after 14m49s
unittests / Test hosting with 3.13 on ubuntu-latest (push) Successful in 5m0s
unittests / Test Python 3.13 macos-latest (push) Has been cancelled
unittests / Test Python 3.11 windows-latest (push) Has been cancelled
unittests / Test Python 3.13 windows-latest (push) Has been cancelled
2136 lines
105 KiB
Python
2136 lines
105 KiB
Python
from typing import TYPE_CHECKING, Callable, Set, ClassVar
|
|
from dataclasses import dataclass, field
|
|
from warnings import warn
|
|
import math
|
|
|
|
from BaseClasses import CollectionState
|
|
from Options import OptionError
|
|
|
|
from .Locations import CAMERAS_INDEX, CAMERAS_MASTER, CELLPHONES_INDEX, Cellphone_Name_to_ID, MONKEYS_BOSSES, \
|
|
MONKEYS_BREAK_ROOMS, MONKEYS_INDEX, MONKEYS_MASTER, MONKEYS_PASSWORDS, generate_name_to_id, LOCATIONS_INDEX, \
|
|
LOCATIONS_DIRECTORY, SHOP_CHEAP_COLLECTION_INDEX, SHOP_CHEAP_MASTER, SHOP_PROGRESSION_DIRECTORY, SHOP_UNIQUE_MASTER, \
|
|
SHOP_COLLECTION_MASTER, SHOP_PERSISTENT_MASTER, SHOP_CHEAP_COLLECTION_MASTER, SHOP_EVENT_ACCESS_DIRECTORY, \
|
|
MONKEYS_INFINITE_GADGET_FLOAT_APPLICABLE, EVENTS_INFINITE_GADGET_FLOAT_APPLICABLE
|
|
from .Logic import Rulesets, AccessRule, has_keys, event_invoked, has_enough_keys, can_access_region, \
|
|
has_shop_stock, has_morph_stocks, has_morph_extensions, can_farm_boxes, can_farm_sneaky_borgs
|
|
from .Strings import Loc, Stage, Events, APHelper
|
|
from .Stages import (STAGES_DIRECTORY, STAGES_DIRECTORY_LABEL, ENTRANCES_SHOP_PSEUDOREGIONS, AE3EntranceMeta,
|
|
ENTRANCES_SHOP_PROGRESSION, STAGES_SHOP_PROGRESSION, STAGES_FARMABLE, STAGES_FARMABLE_SNEAKY_BORG,
|
|
LEVELS_BY_ORDER, ENTRANCES_INFINITE_GADGET_FLOAT_APPLICABLE)
|
|
|
|
if TYPE_CHECKING:
|
|
from ..AE3_Client import AE3Context
|
|
from .. import AE3World, AE3Options
|
|
|
|
|
|
class GoalTarget:
|
|
name : str = "Empty Goal"
|
|
description : str = "A Generic Goal Target"
|
|
|
|
locations : set[str] = {}
|
|
location_ids : set[int] = {}
|
|
|
|
amount : int = 0
|
|
|
|
def __init__(self, amount : int = 0, excluded_stages : list[str] = None, excluded_locations : list[str] = None,
|
|
shop_mode : int = 1):
|
|
if not self.locations:
|
|
return
|
|
|
|
if excluded_locations is None:
|
|
excluded_locations = []
|
|
|
|
if excluded_stages is None:
|
|
excluded_stages = []
|
|
|
|
# Add Extra Locations
|
|
self.locations = {*self.locations}
|
|
|
|
# Exclude Specified Locations if any
|
|
locations_excluded : list[str] = excluded_locations if excluded_locations else []
|
|
if excluded_stages:
|
|
for stage in excluded_stages:
|
|
locations_excluded.extend( locations for locations in MONKEYS_INDEX.get(stage, []) )
|
|
locations_excluded.extend( locations for locations in CAMERAS_INDEX.get(stage, []) )
|
|
locations_excluded.extend( locations for locations in CELLPHONES_INDEX.get(stage, []) )
|
|
|
|
# Exclude Shop Item Locations that are not used
|
|
if shop_mode == 2:
|
|
locations_excluded.extend(set(SHOP_UNIQUE_MASTER).difference(SHOP_PERSISTENT_MASTER))
|
|
else:
|
|
locations_excluded.extend(set(SHOP_COLLECTION_MASTER).difference(SHOP_PERSISTENT_MASTER))
|
|
|
|
if locations_excluded:
|
|
actual : str = "Actual: " if self.locations else "[ No Set Locations ] |"
|
|
for location in self.locations:
|
|
actual += f"{location}, "
|
|
|
|
self.locations.difference_update(set(locations_excluded))
|
|
if len(self.locations) <= 0:
|
|
excluded : str = "Excluded: "
|
|
for stage in excluded_stages:
|
|
excluded += f"{stage}, "
|
|
|
|
for location in locations_excluded:
|
|
excluded += f"{location} | "
|
|
|
|
raise OptionError(f"AE3 > GoalTarget: There are no goal locations available to check. "
|
|
f"They might have been explicitly excluded. Please reduce the excluded locations.",
|
|
f"{actual}", f"{excluded}")
|
|
elif len(self.locations) < self.amount:
|
|
warn("AE3 > GoalTarget :"
|
|
" Number of Locations required to check for Goal has been reduced due to excluded locations.")
|
|
self.amount = len(self.locations)
|
|
|
|
self.location_ids = {generate_name_to_id()[location] for location in self.locations}
|
|
|
|
if amount and amount < 101:
|
|
mod: float = amount / 100
|
|
total_locs: int = len(self.locations)
|
|
new_total: int = int(math.ceil(total_locs * mod))
|
|
if not self.amount or self.amount is None:
|
|
self.amount = total_locs if not amount else min(new_total, total_locs)
|
|
else:
|
|
self.amount = max(min(total_locs, new_total), 0)
|
|
elif not self.amount or self.amount is None:
|
|
self.amount = len(self.locations)
|
|
|
|
def __bool__(self) -> bool:
|
|
return bool(self.amount)
|
|
|
|
def __str__(self):
|
|
return self.name + "\n [ " + self.description + " ]"
|
|
|
|
def exclude(self, locations : list[str] = None):
|
|
if locations is None or not locations:
|
|
self.locations = { location for location in self.locations if location not in locations }
|
|
self.location_ids = {generate_name_to_id()[location] for location in self.locations}
|
|
|
|
def append(self, *locations : str):
|
|
self.locations = { * self.locations, *locations }
|
|
|
|
async def check(self, ctx : 'AE3Context'):
|
|
checked: set[int] = ctx.locations_checked.copy()
|
|
|
|
if len(self.location_ids.intersection(checked)) >= self.amount and not ctx.game_goaled:
|
|
await ctx.goal()
|
|
|
|
def get_progress(self, ctx : 'AE3Context') -> int:
|
|
checked: set[int] = ctx.locations_checked
|
|
progress : int = len(self.location_ids.intersection(checked))
|
|
|
|
return progress
|
|
|
|
def get_remaining(self, ctx : 'AE3Context') -> list[str]:
|
|
checked: set[int] = ctx.locations_checked
|
|
progressed : set[int] = self.location_ids.intersection(checked)
|
|
|
|
name_to_id : dict[str, int] = generate_name_to_id()
|
|
remaining : list[str] = [ l for l in self.locations if name_to_id[l] not in progressed]
|
|
|
|
return remaining
|
|
|
|
def verify(self, state : CollectionState, player : int) -> bool:
|
|
checks : int = 0
|
|
for location in self.locations:
|
|
if not state.can_reach_location(location, player):
|
|
continue
|
|
|
|
checks += 1
|
|
if checks >= self.amount:
|
|
return True
|
|
|
|
return False
|
|
|
|
def enact(self) -> Callable[[CollectionState, int], bool]:
|
|
return lambda state, player : self.verify(state, player)
|
|
|
|
@dataclass
|
|
class PostGameCondition:
|
|
name : str = "No Post Game Access Rule"
|
|
description : str = ""
|
|
passed : bool = False
|
|
|
|
locations : dict[str, set[str]] = field(default_factory=dict)
|
|
location_ids: dict[str, set[int]] = field(default_factory=dict)
|
|
amounts : dict[str, int] = field(default_factory=dict)
|
|
|
|
location_categories : ClassVar[list[str]] = [APHelper.monkey.value,
|
|
APHelper.bosses.value,
|
|
APHelper.camera.value,
|
|
APHelper.cellphone.value,
|
|
APHelper.shop.value]
|
|
|
|
def __init__(self, amounts : dict[str, int], excluded_regions : list[str] = None,
|
|
excluded_locations : list[str] = None, shop_mode : int = 1):
|
|
# Check if at least one Post Game Condition is enabled
|
|
if not amounts or all(_ <= 0 for _ in [*amounts.values()]):
|
|
raise OptionError("AE3 > PostGameCondition: At least one Post-Game Condition must be enabled!")
|
|
|
|
# Initialize
|
|
self.passed : bool = False
|
|
|
|
self.locations = {}
|
|
self.location_ids = {}
|
|
|
|
if excluded_locations is None:
|
|
excluded_locations = []
|
|
|
|
if excluded_regions is None:
|
|
excluded_regions = []
|
|
|
|
# Set amounts
|
|
self.amounts = amounts
|
|
|
|
# Get locations from region to exclude
|
|
if excluded_regions:
|
|
for region in excluded_regions:
|
|
excluded_locations.extend(LOCATIONS_INDEX.get(region, []))
|
|
|
|
# Exclude Shop Item Locations that are not used
|
|
if shop_mode == 2:
|
|
excluded_locations.extend(set(SHOP_UNIQUE_MASTER).difference(SHOP_PERSISTENT_MASTER))
|
|
else:
|
|
excluded_locations.extend(set(SHOP_COLLECTION_MASTER).difference(SHOP_PERSISTENT_MASTER))
|
|
|
|
# Define valid locations for checking
|
|
to_id : dict[str, int] = generate_name_to_id()
|
|
|
|
for category in self.location_categories:
|
|
if category in self.amounts:
|
|
location_list : set[str] = {*LOCATIONS_DIRECTORY.get(category, [])}
|
|
if category == APHelper.monkey.value:
|
|
location_list -= {Loc.boss_tomoki.value}
|
|
elif category == APHelper.cellphone.value:
|
|
location_list = {Cellphone_Name_to_ID[loc] for loc in location_list}
|
|
location_list -= set(excluded_locations)
|
|
|
|
self.locations[category] = {*location_list}
|
|
|
|
# Lower required amount if there are enough excluded locations to make the initial value impossible
|
|
if self.amounts[category] > len(location_list):
|
|
if category == APHelper.shop.value:
|
|
self.amounts[category] = min(len(location_list), len(SHOP_UNIQUE_MASTER))
|
|
else:
|
|
self.amounts[category] = len(location_list)
|
|
|
|
self.location_ids[category] = { to_id[loc] for loc in location_list }
|
|
|
|
def verify(self, state : CollectionState, player : int, min_keys : int, break_rooms : int = 0) -> bool:
|
|
if not has_enough_keys(state, player, min_keys):
|
|
return False
|
|
|
|
rules : set[Callable] = set()
|
|
if any(category in self.amounts for category in self.location_categories[:3]):
|
|
rules.update({AccessRule.CATCH, AccessRule.FLY, AccessRule.DASH, AccessRule.SHOOT})
|
|
highest_scale : float = 0.0
|
|
|
|
if APHelper.monkey.value in self.amounts:
|
|
highest_scale = max(highest_scale, (self.amounts[APHelper.monkey.value] /
|
|
len(self.location_ids[APHelper.monkey.value])))
|
|
if break_rooms >= 2 and self.amounts[APHelper.monkey.value] > 354:
|
|
rules.add(AccessRule.MONKEY)
|
|
|
|
if APHelper.camera.value in self.amounts:
|
|
count : int = sum([state.can_reach_location(camera, player)
|
|
for camera in self.locations[APHelper.camera.value]])
|
|
|
|
if count < self.amounts[APHelper.camera.value]:
|
|
return False
|
|
|
|
if APHelper.cellphone.value in self.amounts:
|
|
highest_scale = max(highest_scale, len(self.location_ids[APHelper.cellphone.value]) / 20)
|
|
|
|
if APHelper.keys.value in self.amounts:
|
|
rules.add(has_keys((min_keys - 1) + self.amounts[APHelper.keys.value]))
|
|
|
|
# Check Rules that only yields small progress if required amount is high enough
|
|
highest_scale *= 100
|
|
if highest_scale > 50:
|
|
rules.update({AccessRule.MAGICIAN, AccessRule.KUNGFU, AccessRule.SWIM})
|
|
if highest_scale > 80:
|
|
rules.update({AccessRule.RCC, AccessRule.SLING})
|
|
|
|
# Check Rules
|
|
if rules:
|
|
if not all(rule(state, player) for rule in rules):
|
|
return False
|
|
|
|
return True
|
|
|
|
def enact(self, min_keys : int, break_rooms : int = 0) -> Callable[[CollectionState, int], bool]:
|
|
return lambda state, player : self.verify(state, player, min_keys, break_rooms)
|
|
|
|
def check(self, ctx : 'AE3Context') -> bool:
|
|
# If already passed, use the cached status instead of checking everything again
|
|
if self.passed:
|
|
return True
|
|
|
|
total_checked : set[int] = ctx.locations_checked.copy()
|
|
|
|
passed : bool = True
|
|
|
|
# Count Checked Locations needed
|
|
for category in self.location_categories:
|
|
if not category in self.amounts or not category in self.location_ids:
|
|
continue
|
|
|
|
passed = passed and len(total_checked.intersection((self.location_ids[category]))) >= self.amounts[category]
|
|
|
|
# Check for keys required on post
|
|
if APHelper.keys.value in self.amounts:
|
|
passed = passed and ctx.keys - (len(ctx.progression.progression) - 3) >= self.amounts[APHelper.keys.value]
|
|
|
|
if passed and ctx.keys >= len(ctx.progression.progression) - 3:
|
|
self.passed = True
|
|
return True
|
|
|
|
self.passed = False
|
|
return False
|
|
|
|
def bypass(self):
|
|
self.passed = True
|
|
|
|
def get_progress(self, ctx : 'AE3Context') -> dict[str, list[int]]:
|
|
total_checked: set[int] = ctx.locations_checked.copy()
|
|
|
|
progress : dict[str, list[int]] = {}
|
|
for category in self.location_categories:
|
|
if category in self.amounts:
|
|
progress[category] = [len(total_checked.intersection((self.location_ids[category]))),
|
|
self.amounts[category]]
|
|
|
|
if APHelper.keys.value in self.amounts:
|
|
progress[APHelper.keys.value] = [ctx.keys,
|
|
len(ctx.progression.progression[:-3]) + self.amounts[APHelper.keys.value]]
|
|
|
|
return progress
|
|
|
|
def get_remaining(self, ctx : 'AE3Context') -> dict[str, list[str]]:
|
|
checked : set[int] = ctx.locations_checked
|
|
|
|
remaining : dict[str, list[str]] = {}
|
|
for category in self.location_categories:
|
|
if category in self.amounts:
|
|
remaining[category] = [location for location in self.locations[category]
|
|
if generate_name_to_id()[location] not in checked]
|
|
|
|
return remaining
|
|
|
|
|
|
class LogicPreference:
|
|
"""
|
|
Base Class for defined RuleTypes. RuleTypes determine the kinds of access rules locations or regions have
|
|
based on a preferred play style
|
|
|
|
Attributes:
|
|
monkey_rules : Rulesets for Monkeys
|
|
event_rules : Rulesets for Events
|
|
entrance_rules : Rulesets for Entrances
|
|
|
|
blacklisted_entrances : Entrances that are excepted from generation and will never be in logic
|
|
|
|
small_starting_channels : Channels with Starting Areas too small that must be actively swapped out from being
|
|
an early level when Shuffle Channel is enabled.
|
|
"""
|
|
monkey_rules : dict[str, Rulesets] = {}
|
|
event_rules : dict[str, Rulesets] = {}
|
|
entrance_rules : dict[str, Rulesets] = {}
|
|
|
|
blacklisted_entrances : list[str] = []
|
|
|
|
default_critical_rule : Set[Callable] = [AccessRule.CATCH]
|
|
small_starting_channels : list[int]
|
|
|
|
def __init__(self):
|
|
self.monkey_rules : dict[str, Rulesets] = {}
|
|
self.event_rules : dict[str, Rulesets] = {}
|
|
self.entrance_rules : dict[str, Rulesets] = {}
|
|
|
|
self.blacklisted_entrances : list[str] = []
|
|
self.minimum_requirements : set[Callable] = set()
|
|
self.edge_requirements : set[Callable] = set()
|
|
self.edge_percentage : int = 0
|
|
|
|
# Get all Access Rules within the channel
|
|
def get_channel_clear_rules(self, *regions : str) -> Rulesets:
|
|
rules : Rulesets = Rulesets()
|
|
if not regions in STAGES_DIRECTORY:
|
|
return rules
|
|
|
|
for region in regions:
|
|
# Entrance Rules
|
|
if region in self.entrance_rules:
|
|
rules.update(self.entrance_rules[region])
|
|
|
|
# Monkey Rules
|
|
rules.critical.update(self.default_critical_rule)
|
|
if region in MONKEYS_INDEX:
|
|
for monkey in MONKEYS_INDEX[region]:
|
|
if monkey in self.monkey_rules:
|
|
rules.rules.extend(self.monkey_rules[monkey].rules)
|
|
|
|
return rules
|
|
|
|
def apply_unlimited_gadget_float_rules(self, hds: bool, mqj: bool):
|
|
if not hds and not mqj:
|
|
return
|
|
|
|
rules: list = []
|
|
if hds:
|
|
rules.append(AccessRule.G_FLOAT)
|
|
if mqj:
|
|
rules.append(AccessRule.QJ)
|
|
|
|
for monkey in MONKEYS_INFINITE_GADGET_FLOAT_APPLICABLE:
|
|
self.monkey_rules.setdefault(monkey, Rulesets()).update(Rulesets(rules))
|
|
|
|
for event in EVENTS_INFINITE_GADGET_FLOAT_APPLICABLE:
|
|
self.event_rules.setdefault(event, Rulesets()).update(Rulesets(rules))
|
|
|
|
for entrance in ENTRANCES_INFINITE_GADGET_FLOAT_APPLICABLE:
|
|
self.entrance_rules.setdefault(entrance, Rulesets()).update(Rulesets(rules))
|
|
|
|
def apply_timed_kung_fu_rule(self, base_duration: int, morph_extensions_enabled: bool):
|
|
# Should only be Implemented by Expert Logic
|
|
return
|
|
|
|
def apply_timed_morph_float(self, base_duration: int, morph_extensions_enabled: bool):
|
|
# Should only be Implemented by Expert Logic
|
|
return
|
|
|
|
def apply_option_logic(self, options: 'AE3Options'):
|
|
# Should be implemented by each LogicPreference as needed
|
|
return
|
|
|
|
# [<--- LOGIC PREFERENCES --->]
|
|
class Hard(LogicPreference):
|
|
"""
|
|
RuleType for a hard experience. The player is assumed to play the game with in-depth knowledge of the game,
|
|
except any glitches major oversights.
|
|
"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
self.small_starting_channels = [6, 18, 20, 22, 23]
|
|
|
|
self.blacklisted_entrances = [
|
|
Stage.entrance_bay_e1e3.value,
|
|
Stage.entrance_bay_e3e4.value,
|
|
Stage.entrance_tomo_f2f.value
|
|
]
|
|
|
|
self.monkey_rules.update({
|
|
# Seaside
|
|
Loc.seaside_morella.value : Rulesets(AccessRule.SHOOT, AccessRule.FLY, AccessRule.MAGICIAN),
|
|
|
|
# Woods
|
|
Loc.woods_kreemon.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Castle
|
|
Loc.castle_monga.value : Rulesets(AccessRule.SHOOT, AccessRule.GLIDE,
|
|
AccessRule.KUNGFU, AccessRule.MAGICIAN),
|
|
|
|
# Studio
|
|
Loc.studio_minoh.value : Rulesets(AccessRule.SHOOT, AccessRule.GLIDE, AccessRule.MAGICIAN),
|
|
Loc.studio_monta.value : Rulesets(AccessRule.SHOOT, AccessRule.GLIDE, AccessRule.MAGICIAN),
|
|
|
|
# Onsen
|
|
Loc.onsen_chabimon.value : Rulesets(AccessRule.RCC, AccessRule.MONKEY),
|
|
|
|
# Snowfesta
|
|
Loc.snowfesta_kimisuke.value : Rulesets(AccessRule.SHOOT),
|
|
Loc.snowfesta_mitsuro.value : Rulesets(AccessRule.SHOOT),
|
|
|
|
# Heaven
|
|
Loc.heaven_chomon.value : Rulesets(AccessRule.RCC, AccessRule.MONKEY),
|
|
|
|
# Toyhouse
|
|
Loc.toyhouse_monto.value : Rulesets(AccessRule.SHOOT, AccessRule.FLY),
|
|
Loc.toyhouse_mokitani.value : Rulesets(AccessRule.RCC),
|
|
|
|
# Iceland
|
|
Loc.iceland_jolly_mon.value : Rulesets(AccessRule.SLING),
|
|
Loc.iceland_hikkori.value : Rulesets(AccessRule.SLING),
|
|
Loc.iceland_rammy.value : Rulesets(AccessRule.SLING),
|
|
|
|
# Arabian
|
|
Loc.arabian_minimon.value : Rulesets(AccessRule.MAGICIAN, AccessRule.DASH),
|
|
|
|
# Asia
|
|
Loc.bay_kazuo.value : Rulesets(AccessRule.NINJA, AccessRule.HERO,
|
|
[AccessRule.SHOOT, AccessRule.SWIM]),
|
|
Loc.asia_mohcha.value : Rulesets(AccessRule.RCC, AccessRule.MONKEY),
|
|
Loc.asia_takumon.value : Rulesets(AccessRule.SWIM, AccessRule.CATCH_LONG,
|
|
[AccessRule.KUNGFU, AccessRule.RCC],
|
|
[AccessRule.KUNGFU, AccessRule.CLUB],
|
|
[AccessRule.KUNGFU, AccessRule.SHOOT],),
|
|
Loc.asia_ukki_ether.value : Rulesets(AccessRule.SWIM, AccessRule.HERO),
|
|
|
|
# Plane
|
|
Loc.plane_mukita.value : Rulesets(AccessRule.MAGICIAN),
|
|
|
|
# Hong
|
|
Loc.hong_ukki_chan.value : Rulesets(AccessRule.SHOOT),
|
|
Loc.hong_uki_uki.value : Rulesets(AccessRule.SHOOT, AccessRule.FLY),
|
|
Loc.hong_muki_muki.value : Rulesets(AccessRule.SHOOT, AccessRule.FLY),
|
|
Loc.hong_bankan.value : Rulesets(AccessRule.GLIDE),
|
|
Loc.hong_sukei.value : Rulesets(AccessRule.SHOOT, AccessRule.NINJA),
|
|
|
|
# Bay
|
|
Loc.bay_shiny_pete.value : Rulesets(AccessRule.SHOOT),
|
|
Loc.bay_gimo.value : Rulesets(AccessRule.SHOOT),
|
|
|
|
# Tomo
|
|
Loc.tomo_riley.value : Rulesets([AccessRule.KUNGFU, AccessRule.MAGICIAN]),
|
|
Loc.tomo_pipo_ron.value : Rulesets(AccessRule.KUNGFU),
|
|
|
|
# Space
|
|
Loc.space_rokkun.value : Rulesets(AccessRule.RCC),
|
|
Loc.space_sal_3000.value : Rulesets(AccessRule.SHOOT),
|
|
})
|
|
|
|
self.event_rules.update({
|
|
# Studio
|
|
Events.studio_b1_button.value : Rulesets(AccessRule.SHOOT, AccessRule.GLIDE,
|
|
AccessRule.MAGICIAN),
|
|
|
|
# Halloween
|
|
Events.halloween_b1_jumbo_robo_shoot.value : Rulesets(AccessRule.SHOOT),
|
|
|
|
# Edotown
|
|
Events.edotown_e_scroll.value : Rulesets(AccessRule.CLUB, AccessRule.HOOP,
|
|
AccessRule.MORPH),
|
|
|
|
# Iceland
|
|
Events.iceland_e_button.value : Rulesets(AccessRule.SLING),
|
|
|
|
# Arabian
|
|
Events.arabian_c_golden_mon.value : Rulesets(AccessRule.CATCH),
|
|
|
|
# Asia
|
|
Events.asia_e1_button.value : Rulesets(AccessRule.RCC, AccessRule.SHOOT,
|
|
critical={AccessRule.FLY}),
|
|
|
|
# Hong
|
|
Events.hong_b_kungfu.value : Rulesets(AccessRule.KUNGFU),
|
|
|
|
# Bay
|
|
Events.bay_e1_button.value : Rulesets(AccessRule.SHOOT),
|
|
|
|
# Tomo
|
|
Events.tomo_e2_kungfu.value : Rulesets(AccessRule.KUNGFU),
|
|
Events.tomo_g_button.value : Rulesets(AccessRule.RCC),
|
|
|
|
# Space
|
|
Events.space_g_button.value : Rulesets(AccessRule.SWIM),
|
|
Events.space_f1_kungfu.value : Rulesets(AccessRule.KUNGFU),
|
|
})
|
|
|
|
self.entrance_rules.update({
|
|
# Seaside
|
|
Stage.entrance_seaside_ac.value : Rulesets(AccessRule.MONKEY),
|
|
|
|
# Woods
|
|
Stage.entrance_woods_ad.value : Rulesets(AccessRule.MONKEY),
|
|
|
|
# Castle
|
|
Stage.entrance_castle_a1a.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_castle_aa2.value : Rulesets(event_invoked(Events.castle_a2_button.value)),
|
|
Stage.entrance_castle_b1b.value : Rulesets(event_invoked(Events.castle_b_clapper.value)),
|
|
Stage.entrance_castle_be.value : Rulesets(AccessRule.MONKEY),
|
|
|
|
# Ciscocity
|
|
Stage.entrance_ciscocity_ad.value : Rulesets(AccessRule.DASH, AccessRule.RCC, AccessRule.KUNGFU),
|
|
Stage.entrance_ciscocity_ad_2.value : Rulesets(event_invoked(Events.ciscocity_d_exit.value)),
|
|
Stage.entrance_ciscocity_ce.value : Rulesets(AccessRule.MONKEY),
|
|
Stage.entrance_ciscocity_c1c.value : Rulesets(event_invoked(Events.ciscocity_c_button.value)),
|
|
Stage.entrance_ciscocity_cc1.value : Rulesets(event_invoked(Events.ciscocity_c_button.value)),
|
|
|
|
# Studio
|
|
Stage.entrance_studio_aa1.value : Rulesets(event_invoked(Events.studio_a1_button.value)),
|
|
Stage.entrance_studio_aa2.value : Rulesets(event_invoked(Events.studio_a2_button.value)),
|
|
Stage.entrance_studio_b1b2.value : Rulesets(event_invoked(Events.studio_b1_button.value)),
|
|
Stage.entrance_studio_b2b.value : Rulesets(event_invoked(Events.studio_b1_button.value)),
|
|
Stage.entrance_studio_bb2.value : Rulesets(event_invoked(Events.studio_b1_button.value)),
|
|
Stage.entrance_studio_ff1.value : Rulesets(event_invoked(Events.studio_f_tele_robo.value)),
|
|
Stage.entrance_studio_f1f.value : Rulesets(event_invoked(Events.studio_f_tele_robo.value)),
|
|
Stage.entrance_studio_dg.value : Rulesets(AccessRule.MONKEY),
|
|
Stage.entrance_studio_dd2.value : Rulesets(AccessRule.SHOOT),
|
|
|
|
# Halloween
|
|
Stage.entrance_halloween_aa1.value : Rulesets(AccessRule.SWIM, AccessRule.HERO),
|
|
Stage.entrance_halloween_a1a.value : Rulesets(AccessRule.SWIM, AccessRule.HERO),
|
|
Stage.entrance_halloween_bb1.value : Rulesets(
|
|
event_invoked(Events.halloween_b_jumbo_robo.value),
|
|
event_invoked(Events.halloween_b1_jumbo_robo_shoot.value)),
|
|
Stage.entrance_halloween_b1b.value: Rulesets(
|
|
event_invoked(Events.halloween_b_jumbo_robo.value),
|
|
event_invoked(Events.halloween_b1_jumbo_robo_shoot.value)),
|
|
Stage.entrance_halloween_c1c.value : Rulesets(AccessRule.SWIM, AccessRule.HERO),
|
|
Stage.entrance_halloween_cc1.value : Rulesets(AccessRule.SWIM, AccessRule.HERO),
|
|
Stage.entrance_halloween_cc2.value : Rulesets(AccessRule.SWIM, AccessRule.GLIDE),
|
|
Stage.entrance_halloween_c2c.value : Rulesets(AccessRule.SWIM, AccessRule.GLIDE),
|
|
Stage.entrance_halloween_d1e.value : Rulesets(AccessRule.MONKEY),
|
|
|
|
# Western
|
|
Stage.entrance_western_ee1.value : Rulesets(AccessRule.GLIDE, AccessRule.SHOOT, AccessRule.KUNGFU,
|
|
AccessRule.MAGICIAN),
|
|
Stage.entrance_western_ec.value : Rulesets(AccessRule.MONKEY),
|
|
|
|
# Onsen
|
|
Stage.entrance_onsen_a1a.value : Rulesets(event_invoked(Events.onsen_a_button.value)),
|
|
Stage.entrance_onsen_a2a.value : Rulesets(event_invoked(Events.onsen_a_button.value)),
|
|
Stage.entrance_onsen_a1b1.value : Rulesets(AccessRule.DASH, AccessRule.RCC),
|
|
Stage.entrance_onsen_a2b1.value : Rulesets(AccessRule.DASH, AccessRule.RCC),
|
|
Stage.entrance_onsen_b1b.value : Rulesets(AccessRule.GLIDE, AccessRule.KUNGFU,
|
|
[AccessRule.RCC, AccessRule.SWIM]),
|
|
Stage.entrance_onsen_be.value : Rulesets(AccessRule.FLY),
|
|
Stage.entrance_onsen_bd1.value : Rulesets(AccessRule.SHOOT, [AccessRule.RCC, AccessRule.ATTACK]),
|
|
Stage.entrance_onsen_bd.value : Rulesets(AccessRule.FLY),
|
|
Stage.entrance_onsen_dd1.value : Rulesets(AccessRule.RCC, AccessRule.DASH),
|
|
Stage.entrance_onsen_d1d.value : Rulesets(AccessRule.RCC),
|
|
Stage.entrance_onsen_dc.value : Rulesets(AccessRule.MONKEY),
|
|
|
|
# Snowfesta
|
|
Stage.entrance_snowfesta_ab.value : Rulesets(AccessRule.RCC, AccessRule.DASH),
|
|
Stage.entrance_snowfesta_ag.value : Rulesets(AccessRule.MONKEY),
|
|
Stage.entrance_snowfesta_ce_2.value : Rulesets(event_invoked(Events.snowfesta_e_bell.value)),
|
|
Stage.entrance_snowfesta_ec.value : Rulesets(event_invoked(Events.snowfesta_e_bell.value)),
|
|
|
|
# Edotown
|
|
Stage.entrance_edotown_b1b2.value : Rulesets(AccessRule.NINJA),
|
|
Stage.entrance_edotown_b2b1.value : Rulesets([event_invoked(Events.edotown_b1_button.value),
|
|
AccessRule.NINJA], AccessRule.SWIM, AccessRule.HERO),
|
|
Stage.entrance_edotown_be.value : Rulesets(event_invoked(Events.edotown_e_scroll.value)),
|
|
Stage.entrance_edotown_df.value : Rulesets(AccessRule.MONKEY),
|
|
Stage.entrance_edotown_eb.value : Rulesets(event_invoked(Events.edotown_e_scroll.value)),
|
|
|
|
# Heaven
|
|
Stage.entrance_heaven_ab.value : Rulesets(AccessRule.GLIDE, AccessRule.KUNGFU,
|
|
AccessRule.MAGICIAN),
|
|
Stage.entrance_heaven_ba.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_heaven_b1b.value : Rulesets(event_invoked(Events.heaven_b_clapper.value)),
|
|
Stage.entrance_heaven_ce.value : Rulesets(AccessRule.MONKEY),
|
|
|
|
# Toyhouse
|
|
Stage.entrance_toyhouse_ae.value : Rulesets(AccessRule.NINJA),
|
|
Stage.entrance_toyhouse_ea.value : Rulesets(AccessRule.NINJA),
|
|
Stage.entrance_toyhouse_dh.value : Rulesets(AccessRule.MONKEY),
|
|
|
|
# Iceland
|
|
Stage.entrance_iceland_a2e.value : Rulesets(event_invoked(Events.iceland_e_button.value)),
|
|
Stage.entrance_iceland_ea2.value : Rulesets(event_invoked(Events.iceland_e_button.value)),
|
|
Stage.entrance_iceland_ef.value : Rulesets(AccessRule.MONKEY),
|
|
Stage.entrance_iceland_cb.value : Rulesets(event_invoked(Events.iceland_c_jumbo_robo.value)),
|
|
|
|
# Arabian
|
|
Stage.entrance_arabian_ac.value : Rulesets([AccessRule.RCC, AccessRule.SLING]),
|
|
Stage.entrance_arabian_ac1.value : Rulesets(event_invoked(Events.arabian_c1_exit.value)),
|
|
Stage.entrance_arabian_cc1.value : Rulesets(event_invoked(Events.arabian_c_golden_mon.value)),
|
|
Stage.entrance_arabian_c1c.value : Rulesets(event_invoked(Events.arabian_c_golden_mon.value)),
|
|
Stage.entrance_arabian_bg.value : Rulesets(event_invoked(Events.arabian_g_exit.value)),
|
|
Stage.entrance_arabian_bf.value : Rulesets(AccessRule.MONKEY),
|
|
Stage.entrance_arabian_e1e.value : Rulesets(AccessRule.MAGICIAN),
|
|
|
|
# Asia
|
|
Stage.entrance_asia_ab.value : Rulesets(AccessRule.SWIM, AccessRule.HERO),
|
|
Stage.entrance_asia_ba.value : Rulesets(AccessRule.SWIM, AccessRule.HERO),
|
|
Stage.entrance_asia_aa1.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_aa5.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_a1a.value : Rulesets(AccessRule.SWIM, AccessRule.HERO),
|
|
Stage.entrance_asia_a1b2.value : Rulesets(AccessRule.SWIM, AccessRule.HERO),
|
|
Stage.entrance_asia_a1a2.value : Rulesets(AccessRule.HERO),
|
|
Stage.entrance_asia_a1a3.value : Rulesets(AccessRule.SWIM, [AccessRule.HERO,
|
|
event_invoked(Events.asia_a2_block.value)]),
|
|
Stage.entrance_asia_a1a4.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_a2a1.value : Rulesets(AccessRule.SWIM, AccessRule.HERO),
|
|
Stage.entrance_asia_a2a3.value : Rulesets([event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value)],
|
|
AccessRule.HERO),
|
|
Stage.entrance_asia_a2a4.value : Rulesets(AccessRule.SWIM, AccessRule.HERO),
|
|
Stage.entrance_asia_a3a1.value : Rulesets(AccessRule.SWIM, [AccessRule.HERO,
|
|
event_invoked(Events.asia_a2_block.value)]),
|
|
Stage.entrance_asia_a3a4.value : Rulesets(AccessRule.SWIM, [AccessRule.HERO,
|
|
event_invoked(Events.asia_a2_block.value)]),
|
|
Stage.entrance_asia_a3a2.value : Rulesets([event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value)],
|
|
AccessRule.HERO),
|
|
Stage.entrance_asia_a3e.value : Rulesets([event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value)]),
|
|
Stage.entrance_asia_a4a1.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_a4a3.value : Rulesets(AccessRule.SWIM, [AccessRule.HERO,
|
|
event_invoked(Events.asia_a2_block.value)]),
|
|
Stage.entrance_asia_a4a5.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_a5a6.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_a6a5.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_bb1.value : Rulesets(AccessRule.SHOOT, AccessRule.FLY),
|
|
Stage.entrance_asia_bb2.value : Rulesets(AccessRule.HERO,
|
|
event_invoked(Events.asia_b2_button.value)),
|
|
Stage.entrance_asia_b1b2.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_b2b1.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_d1a4.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_dd1.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_ef.value : Rulesets(AccessRule.MONKEY),
|
|
Stage.entrance_asia_e1e.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_asia_e1e2.value : Rulesets(AccessRule.SHOOT, [AccessRule.ATTACK, AccessRule.RCC],
|
|
critical={AccessRule.FLY}),
|
|
Stage.entrance_asia_e2e.value : Rulesets([event_invoked(Events.asia_e1_button.value),
|
|
AccessRule.SWIM]),
|
|
|
|
# Plane
|
|
Stage.entrance_plane_aa1.value : Rulesets(AccessRule.NINJA),
|
|
Stage.entrance_plane_ac.value : Rulesets(AccessRule.RCC, AccessRule.DASH, AccessRule.KUNGFU),
|
|
Stage.entrance_plane_cc1.value : Rulesets(AccessRule.MAGICIAN),
|
|
Stage.entrance_plane_cg.value : Rulesets(AccessRule.MONKEY),
|
|
Stage.entrance_plane_dd1.value : Rulesets(AccessRule.GLIDE, AccessRule.KUNGFU),
|
|
Stage.entrance_plane_d1d.value : Rulesets(AccessRule.GLIDE, AccessRule.KUNGFU),
|
|
Stage.entrance_plane_ed1.value : Rulesets(event_invoked(Events.plane_d1_clapper.value)),
|
|
|
|
# Hong
|
|
Stage.entrance_hong_aa1.value : Rulesets(AccessRule.KUNGFU, AccessRule.HERO),
|
|
Stage.entrance_hong_a1a2.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_hong_bb1.value : Rulesets(AccessRule.KUNGFU),
|
|
Stage.entrance_hong_b1b.value : Rulesets(event_invoked(Events.hong_b_kungfu.value)),
|
|
Stage.entrance_hong_bb2.value : Rulesets(event_invoked(Events.hong_b2_button.value)),
|
|
Stage.entrance_hong_b1f.value : Rulesets(AccessRule.MONKEY),
|
|
Stage.entrance_hong_b2b.value : Rulesets(event_invoked(Events.hong_b2_button.value)),
|
|
Stage.entrance_hong_b1c.value : Rulesets(AccessRule.KUNGFU),
|
|
Stage.entrance_hong_cc1.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_hong_cc2.value : Rulesets(AccessRule.FLYER),
|
|
Stage.entrance_hong_c1c.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_hong_c1c2.value : Rulesets(AccessRule.NINJA, AccessRule.HERO),
|
|
Stage.entrance_hong_ee1.value : Rulesets(AccessRule.KUNGFU),
|
|
Stage.entrance_hong_dg.value : Rulesets(AccessRule.KUNGFU),
|
|
|
|
# Bay
|
|
Stage.entrance_bay_aa1.value : Rulesets([AccessRule.SHOOT, AccessRule.SWIM], AccessRule.HERO),
|
|
Stage.entrance_bay_a1a.value : Rulesets(AccessRule.SWIM, AccessRule.HERO),
|
|
Stage.entrance_bay_a1b.value : Rulesets(AccessRule.RCC),
|
|
Stage.entrance_bay_a1a2.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_bay_a2a1.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_bay_a2a3.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_bay_a2e.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_bay_a3a2.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_bay_a3a6.value : Rulesets(event_invoked(Events.bay_a7_button.value)),
|
|
Stage.entrance_bay_a4d1.value : Rulesets(AccessRule.SLING),
|
|
Stage.entrance_bay_a6f.value : Rulesets(AccessRule.MONKEY),
|
|
Stage.entrance_bay_d1d.value : Rulesets(AccessRule.KUNGFU),
|
|
Stage.entrance_bay_ea2.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_bay_ee1.value : Rulesets(AccessRule.SHOOT),
|
|
Stage.entrance_bay_ee2.value : Rulesets(event_invoked(Events.bay_e1_button.value)),
|
|
Stage.entrance_bay_e1e2.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_bay_e2e3.value : Rulesets([AccessRule.FLY, AccessRule.KUNGFU]),
|
|
|
|
# Tomo
|
|
Stage.entrance_tomo_a1a.value : Rulesets(AccessRule.GLIDE, AccessRule.MAGICIAN,
|
|
AccessRule.KUNGFU),
|
|
Stage.entrance_tomo_e1i.value : Rulesets(AccessRule.MONKEY),
|
|
Stage.entrance_tomo_e2e3.value : Rulesets(AccessRule.KUNGFU),
|
|
Stage.entrance_tomo_e3e2.value : Rulesets(event_invoked(Events.tomo_e2_kungfu.value)),
|
|
Stage.entrance_tomo_f1f2.value : Rulesets(AccessRule.NINJA, AccessRule.HERO),
|
|
Stage.entrance_tomo_f2f1.value : Rulesets(AccessRule.NINJA, AccessRule.HERO),
|
|
Stage.entrance_tomo_gg1.value : Rulesets(AccessRule.KUNGFU),
|
|
Stage.entrance_tomo_g1f.value : Rulesets(event_invoked(Events.tomo_g_button.value)),
|
|
Stage.entrance_tomo_h1h.value : Rulesets(AccessRule.GLIDE, AccessRule.KUNGFU),
|
|
Stage.entrance_tomo_ha.value : Rulesets(AccessRule.SHOOT),
|
|
|
|
# Space
|
|
Stage.entrance_space_bi.value : Rulesets([event_invoked(Events.space_e_button.value),
|
|
event_invoked(Events.space_f2_button.value),
|
|
event_invoked(Events.space_g1_button.value),
|
|
event_invoked(Events.space_d_button.value)]),
|
|
Stage.entrance_space_e1e.value : Rulesets(event_invoked(Events.space_e_button.value)),
|
|
Stage.entrance_space_ee1_2.value : Rulesets(event_invoked(Events.space_e_button.value)),
|
|
Stage.entrance_space_e1e_2.value : Rulesets([AccessRule.RCC, AccessRule.ATTACK]),
|
|
Stage.entrance_space_ee1.value : Rulesets(event_invoked(Events.space_e_button.value)),
|
|
Stage.entrance_space_eh.value : Rulesets(AccessRule.MONKEY),
|
|
Stage.entrance_space_gg1.value : Rulesets(event_invoked(Events.space_g1_button.value)),
|
|
Stage.entrance_space_gg1_2.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_space_g1g.value : Rulesets(event_invoked(Events.space_g_button.value)),
|
|
Stage.entrance_space_g1g_2.value : Rulesets(event_invoked(Events.space_g1_button.value)),
|
|
Stage.entrance_space_ff2.value : Rulesets(event_invoked(Events.space_f2_button.value)),
|
|
Stage.entrance_space_ff1.value : Rulesets(AccessRule.GLIDE, AccessRule.KUNGFU),
|
|
Stage.entrance_space_f1f2.value : Rulesets(AccessRule.KUNGFU),
|
|
Stage.entrance_space_f2f1.value : Rulesets(event_invoked(Events.space_f1_kungfu.value)),
|
|
Stage.entrance_space_f2f.value : Rulesets(event_invoked(Events.space_f2_button.value)),
|
|
Stage.entrance_space_dd.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_space_dd_2.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_space_ib.value : Rulesets([event_invoked(Events.space_e_button.value),
|
|
event_invoked(Events.space_f2_button.value),
|
|
event_invoked(Events.space_g1_button.value),
|
|
event_invoked(Events.space_d_button.value)]),
|
|
Stage.entrance_space_jj1.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_space_j1j.value : Rulesets(AccessRule.GLIDE),
|
|
})
|
|
|
|
class Expert(Hard):
|
|
"""
|
|
RuleType for players that want to take advantage of glitches (excluding very powerful ones such as HDS)
|
|
"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
self.blacklisted_entrances = []
|
|
|
|
self.monkey_rules.update({
|
|
Loc.seaside_morella.value: Rulesets(
|
|
AccessRule.SHOOT, AccessRule.FLY, AccessRule.MAGICIAN,
|
|
AccessRule.KUNGFU, AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Loc.castle_monga.value: Rulesets(
|
|
AccessRule.SHOOT, AccessRule.GLIDE, AccessRule.MAGICIAN, AccessRule.KUNGFU,
|
|
AccessRule.QJ, AccessRule.G_FLOAT_M,
|
|
),
|
|
Loc.studio_minoh.value: Rulesets(
|
|
AccessRule.SHOOT, AccessRule.GLIDE, AccessRule.MAGICIAN,
|
|
AccessRule.QJ, AccessRule.G_FLOAT_M,
|
|
),
|
|
Loc.studio_monta.value: Rulesets(
|
|
AccessRule.SHOOT, AccessRule.GLIDE, AccessRule.MAGICIAN,
|
|
AccessRule.QJ, AccessRule.G_FLOAT_M,
|
|
),
|
|
Loc.toyhouse_monto.value: Rulesets(
|
|
AccessRule.SHOOT, AccessRule.NINJA, AccessRule.FLYER,
|
|
AccessRule.KUNGFU, AccessRule.QJ, AccessRule.G_FLOAT_M,
|
|
),
|
|
Loc.toyhouse_mokitani.value: Rulesets(
|
|
AccessRule.RCC,
|
|
AccessRule.FLYER, AccessRule.NINJA
|
|
),
|
|
Loc.snowfesta_mitsuro.value: Rulesets(
|
|
AccessRule.SHOOT,
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Loc.asia_baku.value: Rulesets(
|
|
[AccessRule.SHOOT, AccessRule.SWIM], AccessRule.NINJA, AccessRule.HERO,
|
|
AccessRule.KUNGFU
|
|
),
|
|
Loc.asia_takumon.value: Rulesets(
|
|
AccessRule.SWIM, AccessRule.NINJA, AccessRule.COWBOY, AccessRule.HERO,
|
|
AccessRule.KUNGFU
|
|
),
|
|
Loc.asia_ukki_ether.value: Rulesets(
|
|
AccessRule.SWIM, AccessRule.HERO,
|
|
AccessRule.KUNGFU
|
|
),
|
|
Loc.hong_uki_uki.value: Rulesets(
|
|
AccessRule.SHOOT, AccessRule.FLY,
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M,
|
|
),
|
|
Loc.hong_muki_muki.value: Rulesets(
|
|
AccessRule.SHOOT, AccessRule.FLY,
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M,
|
|
),
|
|
Loc.hong_bankan.value: Rulesets(
|
|
AccessRule.GLIDE,
|
|
AccessRule.KUNGFU
|
|
),
|
|
Loc.hong_sukei.value: Rulesets(
|
|
AccessRule.SHOOT, AccessRule.FLY
|
|
),
|
|
Loc.tomo_riley.value: Rulesets(
|
|
[AccessRule.KUNGFU, AccessRule.MAGICIAN],
|
|
AccessRule.MAGICIAN
|
|
),
|
|
Loc.space_rokkun.value: Rulesets(
|
|
AccessRule.RCC, AccessRule.COWBOY
|
|
)
|
|
})
|
|
|
|
self.event_rules.update({
|
|
Events.studio_b1_button.value: Rulesets(
|
|
AccessRule.SHOOT, AccessRule.GLIDE, AccessRule.MAGICIAN,
|
|
AccessRule.BOOST_JUMP, AccessRule.KUNGFU, AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Events.asia_e1_button.value: Rulesets(
|
|
[AccessRule.FLY, AccessRule.SHOOT], [AccessRule.FLY, AccessRule.RCC],
|
|
[AccessRule.SHOOT, AccessRule.SWIM, AccessRule.KUNGFU],
|
|
[AccessRule.RCC, AccessRule.SWIM, AccessRule.KUNGFU],
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Events.space_g_button.value: Rulesets(AccessRule.SWIM, AccessRule.HERO),
|
|
})
|
|
|
|
self.entrance_rules.update({
|
|
Stage.entrance_seaside_ac.value: Rulesets(
|
|
AccessRule.MONKEY,
|
|
AccessRule.KUNGFU
|
|
),
|
|
Stage.entrance_castle_aa2.value: Rulesets(
|
|
event_invoked(Events.castle_a2_button.value),
|
|
AccessRule.KUNGFU
|
|
),
|
|
Stage.entrance_studio_b1b2.value: Rulesets(
|
|
event_invoked(Events.studio_b1_button.value), AccessRule.MAGICIAN,
|
|
AccessRule.BOOST_JUMP, AccessRule.KUNGFU, AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_halloween_c1c.value: Rulesets(
|
|
AccessRule.SWIM, AccessRule.HERO,
|
|
AccessRule.G_FLOAT_M,
|
|
),
|
|
Stage.entrance_halloween_cc1.value: Rulesets(
|
|
AccessRule.SWIM, AccessRule.HERO,
|
|
AccessRule.G_FLOAT_M,
|
|
),
|
|
Stage.entrance_halloween_cc2.value: Rulesets(
|
|
AccessRule.SWIM, AccessRule.GLIDE,
|
|
AccessRule.KUNGFU, AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_halloween_c2c.value: Rulesets(
|
|
AccessRule.SWIM, AccessRule.GLIDE,
|
|
AccessRule.KUNGFU, AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_western_ec.value: Rulesets(
|
|
AccessRule.KUNGFU, AccessRule.MONKEY,
|
|
),
|
|
Stage.entrance_western_ee1.value: Rulesets(
|
|
AccessRule.GLIDE, AccessRule.SHOOT, AccessRule.KUNGFU, AccessRule.MAGICIAN,
|
|
AccessRule.BOOST_JUMP, AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_onsen_b1b.value: Rulesets(
|
|
[AccessRule.RCC, AccessRule.SWIM], AccessRule.GLIDE, AccessRule.KUNGFU,
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_onsen_be.value: Rulesets(
|
|
AccessRule.FLY,
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_snowfesta_ag.value: Rulesets(
|
|
AccessRule.MONKEY, AccessRule.KUNGFU, AccessRule.HERO, AccessRule.BOOST_FLY
|
|
),
|
|
Stage.entrance_snowfesta_dg.value: Rulesets(
|
|
AccessRule.MONKEY,
|
|
AccessRule.KUNGFU, [AccessRule.QJ, AccessRule.G_FLOAT]
|
|
),
|
|
Stage.entrance_edotown_be.value: Rulesets(
|
|
event_invoked(Events.edotown_e_scroll.value),
|
|
AccessRule.NINJA
|
|
),
|
|
Stage.entrance_edotown_c1c.value: Rulesets(
|
|
AccessRule.NINJA, AccessRule.HERO,
|
|
AccessRule.KUNGFU, AccessRule.QJ, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_edotown_cc1.value: Rulesets(
|
|
AccessRule.NINJA, AccessRule.HERO,
|
|
AccessRule.KUNGFU, AccessRule.QJ, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_heaven_ab.value: Rulesets(
|
|
AccessRule.GLIDE, AccessRule.KUNGFU, AccessRule.MAGICIAN,
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M,
|
|
),
|
|
Stage.entrance_heaven_ba.value: Rulesets(
|
|
AccessRule.GLIDE, AccessRule.KUNGFU,
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M,
|
|
),
|
|
Stage.entrance_arabian_e1e.value: Rulesets(
|
|
AccessRule.MAGICIAN,
|
|
AccessRule.FLY
|
|
),
|
|
Stage.entrance_asia_ab.value: Rulesets(
|
|
AccessRule.SWIM, AccessRule.HERO,
|
|
AccessRule.KUNGFU
|
|
),
|
|
Stage.entrance_asia_ba.value: Rulesets(
|
|
AccessRule.SWIM, AccessRule.HERO,
|
|
AccessRule.KUNGFU
|
|
),
|
|
Stage.entrance_asia_aa5.value: Rulesets(
|
|
AccessRule.SWIM,
|
|
AccessRule.KUNGFU,
|
|
),
|
|
Stage.entrance_asia_a2a1.value: Rulesets(
|
|
AccessRule.SWIM, AccessRule.HERO,
|
|
AccessRule.KUNGFU,
|
|
),
|
|
Stage.entrance_asia_a1b2.value: Rulesets(
|
|
AccessRule.SWIM, AccessRule.HERO,
|
|
AccessRule.KUNGFU,
|
|
),
|
|
Stage.entrance_asia_b2a1.value: Rulesets(
|
|
AccessRule.SWIM, AccessRule.HERO,
|
|
AccessRule.KUNGFU, AccessRule.QJ, AccessRule.G_FLOAT_M,
|
|
),
|
|
Stage.entrance_asia_a1a3.value: Rulesets(
|
|
AccessRule.SWIM,
|
|
[event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value),
|
|
AccessRule.HERO],
|
|
[event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value),
|
|
AccessRule.KUNGFU]
|
|
),
|
|
Stage.entrance_asia_a3a1.value: Rulesets(
|
|
AccessRule.SWIM,
|
|
[event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value),
|
|
AccessRule.HERO],
|
|
[event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value),
|
|
AccessRule.KUNGFU]
|
|
),
|
|
Stage.entrance_asia_a2a3.value: Rulesets(
|
|
[event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value)],
|
|
AccessRule.HERO,
|
|
AccessRule.KUNGFU
|
|
),
|
|
Stage.entrance_asia_a2a4.value: Rulesets(
|
|
AccessRule.SWIM, AccessRule.HERO,
|
|
AccessRule.KUNGFU
|
|
),
|
|
Stage.entrance_asia_a3a4.value: Rulesets(
|
|
AccessRule.SWIM,
|
|
[event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value),
|
|
AccessRule.HERO],
|
|
[event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value),
|
|
AccessRule.KUNGFU]
|
|
),
|
|
Stage.entrance_asia_a4a3.value: Rulesets(
|
|
AccessRule.SWIM,
|
|
[event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value),
|
|
AccessRule.HERO],
|
|
[event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value),
|
|
AccessRule.KUNGFU]
|
|
),
|
|
Stage.entrance_asia_a3a2.value: Rulesets(
|
|
[event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value)],
|
|
AccessRule.HERO,
|
|
AccessRule.KUNGFU
|
|
),
|
|
Stage.entrance_asia_bb2.value: Rulesets(
|
|
[event_invoked(Events.asia_b2_button.value)], AccessRule.HERO,
|
|
AccessRule.BOOST_FLY, AccessRule.KUNGFU, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_asia_e1e2.value: Rulesets(
|
|
[AccessRule.SHOOT, AccessRule.FLY],
|
|
[AccessRule.ATTACK, AccessRule.RCC, AccessRule.FLY],
|
|
[AccessRule.HERO, has_morph_stocks(1)],
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_plane_cg.value: Rulesets(
|
|
AccessRule.MONKEY,
|
|
AccessRule.KUNGFU
|
|
),
|
|
Stage.entrance_plane_dd1.value: Rulesets(
|
|
AccessRule.GLIDE, AccessRule.MORPH,
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_plane_d1d.value: Rulesets(
|
|
AccessRule.GLIDE, AccessRule.KUNGFU,
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_hong_aa1.value: Rulesets(
|
|
AccessRule.KUNGFU, AccessRule.HERO,
|
|
AccessRule.BOOST_FLY, AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_hong_b1f.value: Rulesets(
|
|
AccessRule.MONKEY, AccessRule.KUNGFU, AccessRule.HERO
|
|
),
|
|
Stage.entrance_hong_bb1.value: Rulesets(
|
|
AccessRule.KUNGFU,
|
|
AccessRule.BOOST_FLY, AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_hong_b1c.value: Rulesets(
|
|
AccessRule.KUNGFU,
|
|
AccessRule.BOOST_FLY, AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_hong_cc1.value: Rulesets(
|
|
AccessRule.GLIDE, AccessRule.KUNGFU,
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_hong_cc2.value: Rulesets(
|
|
AccessRule.FLYER,
|
|
AccessRule.QJ, AccessRule.G_FLOAT
|
|
),
|
|
Stage.entrance_hong_c1c.value: Rulesets(
|
|
AccessRule.GLIDE, AccessRule.KUNGFU,
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_hong_ee1.value: Rulesets(
|
|
AccessRule.KUNGFU,
|
|
AccessRule.BOOST_FLY, AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_hong_dg.value: Rulesets(
|
|
AccessRule.KUNGFU, [AccessRule.QJ, AccessRule.G_FLOAT], AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_bay_aa1.value: Rulesets(
|
|
[AccessRule.SHOOT, AccessRule.SWIM], AccessRule.HERO, AccessRule.FLYER, AccessRule.MAGICIAN,
|
|
AccessRule.KUNGFU, [AccessRule.SWIM, AccessRule.QJ], [AccessRule.SWIM, AccessRule.G_FLOAT],
|
|
AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_bay_a1a.value: Rulesets(
|
|
[AccessRule.SHOOT, AccessRule.SWIM], AccessRule.HERO, AccessRule.FLYER,
|
|
AccessRule.KUNGFU, [AccessRule.SWIM, AccessRule.QJ], [AccessRule.SWIM, AccessRule.G_FLOAT],
|
|
AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_bay_a6f.value: Rulesets(
|
|
AccessRule.MONKEY,
|
|
AccessRule.KUNGFU, [AccessRule.SWIM, AccessRule.FLYER]
|
|
),
|
|
Stage.entrance_bay_d1d.value: Rulesets(
|
|
AccessRule.KUNGFU,
|
|
AccessRule.BOOST_FLY, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_bay_ee2.value: Rulesets(
|
|
AccessRule.FLYER, AccessRule.NINJA, AccessRule.QJ,
|
|
[AccessRule.G_FLOAT, AccessRule.CLUB], [AccessRule.MONKEY, AccessRule.CLUB]
|
|
),
|
|
Stage.entrance_bay_e3e4.value: Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_tomo_a1a.value: Rulesets(
|
|
AccessRule.GLIDE, AccessRule.MAGICIAN, AccessRule.KUNGFU,
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_tomo_f1f2.value: Rulesets(
|
|
AccessRule.NINJA, AccessRule.HERO,
|
|
AccessRule.KUNGFU, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_tomo_f2f1.value: Rulesets(
|
|
AccessRule.NINJA, AccessRule.HERO,
|
|
AccessRule.KUNGFU, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_tomo_f2f.value: Rulesets(AccessRule.FLY),
|
|
Stage.entrance_tomo_gg1.value: Rulesets(
|
|
AccessRule.KUNGFU,
|
|
AccessRule.BOOST_FLY, AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_tomo_h1h.value: Rulesets(
|
|
AccessRule.GLIDE, AccessRule.KUNGFU, AccessRule.MAGICIAN,
|
|
AccessRule.QJ, AccessRule.G_FLOAT, AccessRule.G_FLOAT_M
|
|
),
|
|
Stage.entrance_space_bi.value: Rulesets(
|
|
[event_invoked(Events.space_e_button.value),
|
|
event_invoked(Events.space_f2_button.value),
|
|
event_invoked(Events.space_g1_button.value),
|
|
event_invoked(Events.space_d_button.value)],
|
|
AccessRule.HERO,
|
|
),
|
|
Stage.entrance_space_ff1.value: Rulesets(
|
|
AccessRule.GLIDE,
|
|
AccessRule.MORPH, AccessRule.BOOST_JUMP, AccessRule.QJ, AccessRule.G_FLOAT
|
|
)
|
|
})
|
|
|
|
monkeys_to_reset: list = [
|
|
Loc.heaven_chomon.value,
|
|
Loc.arabian_minimon.value,
|
|
Loc.snowfesta_kimisuke.value,
|
|
Loc.asia_mohcha.value,
|
|
Loc.plane_mukita.value,
|
|
]
|
|
|
|
for monkey in monkeys_to_reset:
|
|
if monkey in self.monkey_rules:
|
|
self.monkey_rules.pop(monkey)
|
|
|
|
entrances_to_reset: list = [
|
|
Stage.entrance_seaside_ac.value,
|
|
Stage.entrance_woods_ad.value,
|
|
Stage.entrance_castle_ad.value,
|
|
Stage.entrance_ciscocity_ad_2.value,
|
|
Stage.entrance_ciscocity_c1c.value,
|
|
Stage.entrance_ciscocity_ce.value,
|
|
Stage.entrance_studio_dg.value,
|
|
Stage.entrance_onsen_dd1.value,
|
|
Stage.entrance_heaven_ce.value,
|
|
Stage.entrance_snowfesta_ab.value,
|
|
Stage.entrance_edotown_df.value,
|
|
Stage.entrance_iceland_ef.value,
|
|
Stage.entrance_plane_cc1.value,
|
|
Stage.entrance_plane_cg.value,
|
|
Stage.entrance_bay_a1b.value,
|
|
Stage.entrance_tomo_e1i.value,
|
|
Stage.entrance_space_e1e_2.value,
|
|
Stage.entrance_space_eh.value,
|
|
Stage.entrance_space_gg1.value,
|
|
Stage.entrance_space_f1f2.value
|
|
]
|
|
for entrance in entrances_to_reset:
|
|
if entrance in self.entrance_rules:
|
|
self.entrance_rules.pop(entrance)
|
|
|
|
def apply_timed_kungfu_rule(self, base_duration: int, morph_extensions_enabled: bool):
|
|
locations: list = [
|
|
Loc.edotown_monkibeth.value
|
|
]
|
|
|
|
rules: list = [AccessRule.KUNGFU]
|
|
if base_duration < 30 and morph_extensions_enabled:
|
|
rules.append(has_morph_extensions())
|
|
|
|
for loc in locations:
|
|
self.monkey_rules.get(loc, Rulesets()).update(Rulesets(rules))
|
|
|
|
|
|
self.entrance_rules.get(Stage.entrance_asia_e1e2.value, Rulesets()).update(
|
|
Rulesets([AccessRule.SHOOT, AccessRule.SWIM, *rules],
|
|
[AccessRule.ATTACK, AccessRule.RCC, AccessRule.SWIM, *rules],)
|
|
)
|
|
|
|
self.event_rules.get(Events.space_g_button.value, Rulesets()).update(Rulesets(AccessRule.KUNGFU))
|
|
|
|
def apply_timed_morph_float(self, base_duration: int, morph_extensions_enabled: bool):
|
|
events: list = [
|
|
Events.iceland_e_button.value
|
|
]
|
|
|
|
entrances: list = [
|
|
Stage.entrance_halloween_aa1.value,
|
|
Stage.entrance_halloween_a1a.value,
|
|
Stage.entrance_halloween_c1c.value,
|
|
Stage.entrance_halloween_cc1.value,
|
|
Stage.entrance_heaven_aa1.value,
|
|
Stage.entrance_heaven_a1a.value,
|
|
Stage.entrance_asia_ab.value,
|
|
Stage.entrance_asia_ba.value,
|
|
Stage.entrance_asia_a1a2.value,
|
|
Stage.entrance_asia_a1a3.value,
|
|
Stage.entrance_asia_a3a1.value,
|
|
Stage.entrance_asia_a2a3.value,
|
|
Stage.entrance_asia_a3a2.value,
|
|
Stage.entrance_asia_a2a4.value,
|
|
Stage.entrance_asia_a3a4.value,
|
|
Stage.entrance_hong_c1c2.value,
|
|
Stage.entrance_hong_cc2.value,
|
|
]
|
|
|
|
rules: list = [AccessRule.G_FLOAT_M]
|
|
if base_duration < 30 and morph_extensions_enabled:
|
|
rules.append(has_morph_extensions())
|
|
|
|
for e in events:
|
|
self.event_rules.get(e, Rulesets()).update(Rulesets(rules))
|
|
|
|
for e in entrances:
|
|
self.entrance_rules.get(e, Rulesets()).update(Rulesets(rules))
|
|
|
|
def apply_option_logic(self, options: 'AE3Options'):
|
|
if options.shoppingsanity.value < 1:
|
|
rules: list = [AccessRule.HERO, can_farm_boxes()]
|
|
if options.farm_logic_sneaky_borgs:
|
|
rules.append(can_farm_sneaky_borgs())
|
|
|
|
self.entrance_rules.get(Stage.entrance_asia_e1e2.value, Rulesets()).update(Rulesets(rules))
|
|
|
|
class Normal(Hard):
|
|
"""
|
|
RuleType for a normal experience. Expectations of accessibility will be the same as the vanilla game.
|
|
"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
self.small_starting_channels = [6, 9, 11, 15, 18, 20, 22, 23]
|
|
self.blacklisted_entrances = [
|
|
Stage.entrance_hong_cc2.value,
|
|
Stage.entrance_bay_e1e3.value,
|
|
Stage.entrance_bay_e3e4.value,
|
|
Stage.entrance_tomo_f2f.value
|
|
]
|
|
|
|
self.monkey_rules.update({
|
|
# Seaside
|
|
Loc.seaside_morella.value : Rulesets(AccessRule.SHOOT, AccessRule.FLY),
|
|
|
|
# Woods
|
|
Loc.woods_salubon.value : Rulesets(AccessRule.HIT),
|
|
Loc.woods_ukkilei.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Castle
|
|
Loc.castle_pipo_guard.value : Rulesets(AccessRule.HIT),
|
|
Loc.castle_ukkii.value : Rulesets(AccessRule.HIT),
|
|
Loc.castle_sal_1000.value : Rulesets(AccessRule.HIT),
|
|
Loc.castle_monga.value : Rulesets(AccessRule.SHOOT, AccessRule.GLIDE,
|
|
AccessRule.MAGICIAN),
|
|
|
|
# Ciscocity
|
|
Loc.ciscocity_pipo_mondy.value : Rulesets(AccessRule.DASH),
|
|
|
|
# Studio
|
|
Loc.studio_monpii_ukkichi.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Halloween
|
|
Loc.halloween_uikkun.value : Rulesets(AccessRule.HIT),
|
|
Loc.halloween_bonbon.value : Rulesets(AccessRule.HIT,
|
|
event_invoked(Events.halloween_b_jumbo_robo.value),
|
|
event_invoked(Events.halloween_b1_jumbo_robo_shoot.value)),
|
|
Loc.halloween_chichi.value : Rulesets(AccessRule.HIT,
|
|
event_invoked(Events.halloween_b_jumbo_robo.value),
|
|
event_invoked(Events.halloween_b1_jumbo_robo_shoot.value)),
|
|
Loc.halloween_ukkito.value : Rulesets(AccessRule.HIT),
|
|
Loc.halloween_ukkiami.value : Rulesets(AccessRule.HIT),
|
|
Loc.halloween_kabochin.value : Rulesets(AccessRule.HIT),
|
|
Loc.halloween_mumpkin.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Western
|
|
Loc.western_jay_mohn.value : Rulesets(AccessRule.HIT),
|
|
Loc.western_jaja_jamo.value : Rulesets(AccessRule.ATTACK, AccessRule.HOOP),
|
|
Loc.western_chammy_mo.value : Rulesets(AccessRule.HIT),
|
|
Loc.western_golozo.value : Rulesets(AccessRule.HIT),
|
|
Loc.western_golon_moe.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Onsen
|
|
Loc.onsen_chabimon.value : Rulesets(AccessRule.RCC),
|
|
Loc.onsen_domobeh.value : Rulesets(AccessRule.SWIM, AccessRule.CATCH_LONG),
|
|
Loc.onsen_mujakin.value : Rulesets(AccessRule.SWIM, AccessRule.CATCH_LONG),
|
|
Loc.onsen_fuji_chan.value : Rulesets(AccessRule.SHOOT, AccessRule.GLIDE),
|
|
|
|
# Snofesta
|
|
Loc.snowfesta_konkichi.value : Rulesets(AccessRule.RADAR),
|
|
Loc.snowfesta_pipotron_yellow.value : Rulesets(AccessRule.DASH),
|
|
Loc.snowfesta_ukki_jii.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Edotown
|
|
Loc.edotown_fatty_mcfats.value : Rulesets(AccessRule.HIT),
|
|
Loc.edotown_walter.value : Rulesets(AccessRule.NINJA),
|
|
|
|
# Heaven
|
|
Loc.heaven_chomon.value : Rulesets(AccessRule.RCC),
|
|
Loc.heaven_ukkido.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.heaven_tami.value : Rulesets(AccessRule.HIT),
|
|
Loc.heaven_valuccha.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Toyhouse
|
|
Loc.toyhouse_monto.value : Rulesets(AccessRule.SHOOT, AccessRule.NINJA),
|
|
Loc.toyhouse_golonero.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Iceland
|
|
Loc.iceland_kushachin.value : Rulesets(AccessRule.HIT),
|
|
Loc.iceland_malikko.value : Rulesets(AccessRule.HIT),
|
|
Loc.iceland_bolikko.value : Rulesets(AccessRule.HIT),
|
|
Loc.iceland_iceymon.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Arabian
|
|
Loc.arabian_minimon.value : Rulesets(AccessRule.MAGICIAN),
|
|
Loc.arabian_cup_o_mon.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Asia
|
|
Loc.asia_mohcha.value : Rulesets(AccessRule.RCC),
|
|
Loc.asia_baku.value : Rulesets([AccessRule.SHOOT, AccessRule.SWIM], AccessRule.NINJA),
|
|
Loc.asia_takumon.value : Rulesets(AccessRule.SWIM, AccessRule.CATCH_LONG),
|
|
Loc.asia_ukki_ether.value : Rulesets(AccessRule.SWIM),
|
|
|
|
# Plane
|
|
Loc.plane_jeloh.value : Rulesets(AccessRule.HIT),
|
|
Loc.plane_bongo.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Bay
|
|
Loc.bay_nadamon.value : Rulesets(AccessRule.HIT),
|
|
Loc.bay_nakabi.value : Rulesets(AccessRule.HIT),
|
|
Loc.bay_gimi_gimi.value : Rulesets(AccessRule.HIT),
|
|
Loc.bay_pokkini.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Tomo
|
|
Loc.tomo_kichibeh.value : Rulesets(AccessRule.HIT),
|
|
Loc.tomo_bonchicchi.value : Rulesets(AccessRule.HIT),
|
|
Loc.tomo_mikibon.value : Rulesets(AccessRule.HIT),
|
|
Loc.tomo_chimpy.value : Rulesets(AccessRule.MORPH_NO_MONKEY),
|
|
Loc.tomo_kajitan.value : Rulesets(AccessRule.MORPH_NO_MONKEY),
|
|
Loc.tomo_uka_uka.value : Rulesets(AccessRule.MORPH_NO_MONKEY),
|
|
Loc.tomo_mil_mil.value : Rulesets(AccessRule.MORPH_NO_MONKEY),
|
|
Loc.tomo_tomio.value : Rulesets(AccessRule.HIT),
|
|
Loc.tomo_gario.value : Rulesets(AccessRule.HIT),
|
|
Loc.tomo_sal_13.value : Rulesets(AccessRule.HIT),
|
|
Loc.tomo_sal_12.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Space
|
|
Loc.space_freet.value : Rulesets(AccessRule.HIT),
|
|
Loc.space_chico.value : Rulesets(AccessRule.HIT),
|
|
Loc.space_ukki_love.value : Rulesets(AccessRule.MAGICIAN),
|
|
Loc.space_sal_10.value : Rulesets(AccessRule.HIT),
|
|
Loc.space_sal_11.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Bosses
|
|
Loc.boss_monkey_white.value : Rulesets(AccessRule.HIT),
|
|
Loc.boss_monkey_blue.value : Rulesets(AccessRule.HIT),
|
|
Loc.boss_monkey_yellow.value : Rulesets(AccessRule.HIT),
|
|
Loc.boss_monkey_pink.value : Rulesets(AccessRule.HIT),
|
|
Loc.boss_monkey_red.value : Rulesets(AccessRule.HIT),
|
|
Loc.boss_specter.value : Rulesets([AccessRule.HIT, AccessRule.SHOOT]),
|
|
Loc.boss_specter_final.value : Rulesets(AccessRule.HIT)
|
|
})
|
|
|
|
self.event_rules.update({
|
|
# Castle
|
|
Events.castle_b_clapper.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Ciscocity
|
|
Events.ciscocity_c_button.value : Rulesets(AccessRule.SHOOT, AccessRule.DASH, AccessRule.RCC),
|
|
|
|
# Studio
|
|
Events.studio_a1_button.value : Rulesets(AccessRule.HIT),
|
|
Events.studio_a2_button.value : Rulesets(AccessRule.HIT),
|
|
Events.studio_b1_button.value : Rulesets(AccessRule.SHOOT, AccessRule.GLIDE),
|
|
|
|
# Halloween
|
|
Events.halloween_b_jumbo_robo.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Onsen
|
|
Events.onsen_a_button.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Snowfesta
|
|
Events.snowfesta_e_bell.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Edotown
|
|
Events.edotown_b1_button.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Heaven
|
|
Events.heaven_b_clapper.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Iceland
|
|
Events.iceland_c_jumbo_robo.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Asia
|
|
Events.asia_b2_button.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Plane
|
|
Events.plane_d1_clapper.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Hong
|
|
Events.hong_b2_button.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Bay
|
|
Events.bay_a7_button.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Space
|
|
Events.space_e_button.value : Rulesets(AccessRule.ATTACK),
|
|
Events.space_g1_button.value : Rulesets(AccessRule.ATTACK),
|
|
Events.space_f2_button.value : Rulesets(AccessRule.ATTACK),
|
|
})
|
|
|
|
self.entrance_rules.update({
|
|
# Seaside
|
|
Stage.entrance_seaside_ab.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Woods
|
|
Stage.entrance_woods_bc.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Castle
|
|
Stage.entrance_castle_bb1.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Ciscocity
|
|
Stage.entrance_ciscocity_ad.value : Rulesets(AccessRule.DASH, AccessRule.RCC),
|
|
|
|
# Halloween
|
|
Stage.entrance_halloween_d1d2.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Western
|
|
Stage.entrance_western_bb1.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_western_dd2.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_western_d1d2.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_western_d2d.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_western_ee1.value : Rulesets(AccessRule.GLIDE, AccessRule.SHOOT),
|
|
Stage.entrance_western_ed1.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Onsen
|
|
Stage.entrance_onsen_aa1.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_onsen_aa2.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_onsen_a1a2.value : Rulesets(AccessRule.GLIDE, AccessRule.MAGICIAN),
|
|
Stage.entrance_onsen_a2a1.value : Rulesets(AccessRule.GLIDE, AccessRule.MAGICIAN),
|
|
Stage.entrance_onsen_a1a1m.value : Rulesets(AccessRule.GLIDE, AccessRule.MAGICIAN),
|
|
Stage.entrance_onsen_a2a2m.value : Rulesets(AccessRule.GLIDE, AccessRule.MAGICIAN),
|
|
Stage.entrance_onsen_b1b.value : Rulesets(AccessRule.GLIDE, [AccessRule.RCC, AccessRule.SWIM]),
|
|
|
|
# Edotown
|
|
Stage.entrance_edotown_a1a.value : Rulesets(AccessRule.NINJA, AccessRule.HERO),
|
|
Stage.entrance_edotown_aa1.value : Rulesets(AccessRule.NINJA, AccessRule.HERO),
|
|
Stage.entrance_edotown_ab1.value : Rulesets(AccessRule.NINJA, AccessRule.HERO),
|
|
Stage.entrance_edotown_b1a.value : Rulesets(AccessRule.NINJA, AccessRule.HERO),
|
|
Stage.entrance_edotown_b2b.value : Rulesets(AccessRule.NINJA, AccessRule.HERO),
|
|
Stage.entrance_edotown_bb2.value : Rulesets(AccessRule.NINJA, AccessRule.HERO),
|
|
Stage.entrance_edotown_bc1.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_edotown_c1c.value : Rulesets(AccessRule.NINJA, AccessRule.HERO),
|
|
Stage.entrance_edotown_cc1.value : Rulesets(AccessRule.NINJA, AccessRule.HERO),
|
|
Stage.entrance_edotown_cc2.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Heaven
|
|
Stage.entrance_heaven_a1a.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_heaven_aa1.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_heaven_ab.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_heaven_bb1.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Toyhouse
|
|
Stage.entrance_toyhouse_bb1.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_toyhouse_ef.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_toyhouse_fe.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_toyhouse_fa.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Iceland
|
|
Stage.entrance_iceland_a1a.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Asia
|
|
Stage.entrance_asia_a4d1.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_asia_bb2.value : Rulesets(event_invoked(Events.asia_b2_button.value)),
|
|
Stage.entrance_asia_b2b.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_asia_ee1.value : Rulesets(AccessRule.DASH, AccessRule.RCC),
|
|
|
|
# Plane
|
|
Stage.entrance_plane_ac.value : Rulesets(AccessRule.RCC, AccessRule.DASH),
|
|
Stage.entrance_plane_b1h.value : Rulesets(AccessRule.RCC, AccessRule.HERO),
|
|
Stage.entrance_plane_hb1.value : Rulesets(AccessRule.RCC, AccessRule.HERO),
|
|
Stage.entrance_plane_b1b2.value : Rulesets(AccessRule.RCC, AccessRule.HERO),
|
|
Stage.entrance_plane_b2b1.value : Rulesets(AccessRule.RCC, AccessRule.HERO),
|
|
Stage.entrance_plane_dd1.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_plane_d1d.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_plane_d1e.value : Rulesets(AccessRule.HIT),
|
|
|
|
# Bay
|
|
Stage.entrance_bay_cc1.value : Rulesets(AccessRule.HIT),
|
|
Stage.entrance_bay_e2e3.value : Rulesets([AccessRule.FLY, AccessRule.SWIM, AccessRule.KUNGFU]),
|
|
|
|
# Tomo
|
|
Stage.entrance_tomo_aa1.value : Rulesets(AccessRule.HERO, AccessRule.NINJA),
|
|
Stage.entrance_tomo_a1a.value : Rulesets(AccessRule.HERO, AccessRule.NINJA),
|
|
Stage.entrance_tomo_ee1.value : Rulesets(AccessRule.KNIGHT),
|
|
Stage.entrance_tomo_ee2.value : Rulesets(AccessRule.RCC),
|
|
Stage.entrance_tomo_h1h.value : Rulesets(AccessRule.GLIDE),
|
|
|
|
# Space
|
|
Stage.entrance_space_ab.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_space_e1e_2.value : Rulesets([AccessRule.RCC, AccessRule.MORPH_NO_MONKEY]),
|
|
})
|
|
|
|
class Casual(Normal):
|
|
"""
|
|
RuleType for a casual experience. The player is assumed to play the game without any or little advanced or obscure
|
|
knowledge of it.
|
|
"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
self.small_starting_channels = [6, 9, 11, 13, 15, 18, 20, 22, 23]
|
|
self.blacklisted_entrances = [
|
|
Stage.entrance_asia_a1a2.value,
|
|
Stage.entrance_bay_e1e3.value,
|
|
Stage.entrance_bay_e3e4.value,
|
|
Stage.entrance_tomo_f2f.value
|
|
]
|
|
|
|
self.monkey_rules.update({
|
|
# Woods
|
|
Loc.woods_salubon.value : Rulesets([AccessRule.RADAR, AccessRule.ATTACK]),
|
|
Loc.woods_ukkilei.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Castle
|
|
Loc.castle_pipo_guard.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.castle_monga.value : Rulesets(AccessRule.SHOOT),
|
|
Loc.castle_ukkii.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.castle_sal_1000.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Ciscocity
|
|
Loc.ciscocity_ukima.value : Rulesets(AccessRule.DASH),
|
|
Loc.ciscocity_pipo_mondy.value : Rulesets([AccessRule.ATTACK, AccessRule.DASH]),
|
|
|
|
# Studio
|
|
Loc.studio_minoh.value : Rulesets(AccessRule.SHOOT),
|
|
Loc.studio_monta.value : Rulesets(AccessRule.SHOOT),
|
|
Loc.studio_monpii_ukkichi.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Halloween
|
|
Loc.halloween_monkichiro.value : Rulesets(AccessRule.SWIM),
|
|
Loc.halloween_uikkun.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.halloween_bonbon.value : Rulesets(AccessRule.ATTACK, event_invoked(
|
|
Events.halloween_b_jumbo_robo.value), event_invoked(
|
|
Events.halloween_b1_jumbo_robo_shoot.value)),
|
|
Loc.halloween_chichi.value : Rulesets(AccessRule.ATTACK, event_invoked(
|
|
Events.halloween_b_jumbo_robo.value), event_invoked(
|
|
Events.halloween_b1_jumbo_robo_shoot.value)),
|
|
Loc.halloween_ukkito.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.halloween_ukkiami.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.halloween_kabochin.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.halloween_mumpkin.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Western
|
|
Loc.western_jay_mohn.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.western_jaja_jamo.value : Rulesets(AccessRule.ATTACK, AccessRule.HOOP),
|
|
Loc.western_chammy_mo.value : Rulesets(AccessRule.SHOOT, AccessRule.FLY),
|
|
Loc.western_golozo.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.western_golon_moe.value : Rulesets(AccessRule.MORPH_NO_MONKEY),
|
|
|
|
# Onsen
|
|
Loc.onsen_saru_sam.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.onsen_tome_san.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.onsen_domobeh.value : Rulesets(AccessRule.SWIM),
|
|
Loc.onsen_kimi_san.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.onsen_mujakin.value : Rulesets(AccessRule.SWIM),
|
|
|
|
# Snowfesta
|
|
Loc.snowfesta_konkichi.value : Rulesets([AccessRule.ATTACK, AccessRule.RADAR]),
|
|
Loc.snowfesta_pipotron_yellow.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.snowfesta_ukki_jii.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Edotown
|
|
Loc.edotown_yosio.value : Rulesets(AccessRule.DASH),
|
|
Loc.edotown_fatty_mcfats.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.edotown_golota.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Heaven
|
|
Loc.heaven_ukkido.value : Rulesets(AccessRule.SHOOT),
|
|
Loc.heaven_tami.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.heaven_kicchino.value : Rulesets(AccessRule.MORPH_NO_MONKEY),
|
|
Loc.heaven_kimurin.value : Rulesets(AccessRule.MORPH_NO_MONKEY),
|
|
Loc.heaven_valuccha.value : Rulesets(AccessRule.SHOOT),
|
|
|
|
# Toyhouse
|
|
Loc.toyhouse_monto.value : Rulesets(AccessRule.SHOOT),
|
|
Loc.toyhouse_pipotron_red.value : Rulesets(AccessRule.MORPH_NO_MONKEY),
|
|
Loc.toyhouse_golonero.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Iceland
|
|
Loc.iceland_kushachin.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.iceland_malikko.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.iceland_bolikko.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.iceland_iceymon.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Arabian
|
|
Loc.arabian_cup_o_mon.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Asia
|
|
Loc.asia_baku.value : Rulesets([AccessRule.SHOOT, AccessRule.SWIM]),
|
|
Loc.asia_takumon.value : Rulesets(AccessRule.SWIM),
|
|
|
|
# Plane
|
|
Loc.plane_temko.value : Rulesets(AccessRule.DASH),
|
|
Loc.plane_pipotron_blue.value : Rulesets(AccessRule.MORPH_NO_MONKEY),
|
|
Loc.plane_jeloh.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.plane_bongo.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Hong
|
|
Loc.hong_uki_uki.value : Rulesets(AccessRule.SHOOT),
|
|
Loc.hong_muki_muki.value : Rulesets(AccessRule.SHOOT),
|
|
Loc.hong_bassili_ukki.value : Rulesets(AccessRule.DASH),
|
|
Loc.hong_bankan.value : Rulesets(AccessRule.NINJA),
|
|
Loc.hong_sukei.value : Rulesets(AccessRule.SHOOT),
|
|
|
|
# Bay
|
|
Loc.bay_nadamon.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.bay_nakabi.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.bay_gimi_gimi.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.bay_pokkini.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Tomo
|
|
Loc.tomo_kichibeh.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.tomo_bonchicchi.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.tomo_mikibon.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.tomo_dj_tamo.value : Rulesets(AccessRule.DASH),
|
|
Loc.tomo_chimpy.value : Rulesets(AccessRule.KUNGFU, AccessRule.NINJA),
|
|
Loc.tomo_kajitan.value : Rulesets(AccessRule.KUNGFU, AccessRule.NINJA),
|
|
Loc.tomo_uka_uka.value : Rulesets(AccessRule.KUNGFU, AccessRule.NINJA),
|
|
Loc.tomo_mil_mil.value : Rulesets(AccessRule.KUNGFU, AccessRule.NINJA),
|
|
Loc.tomo_goro_san.value : Rulesets(AccessRule.KNIGHT),
|
|
Loc.tomo_tomio.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.tomo_gario.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.tomo_dj_pari.value : Rulesets(AccessRule.DASH),
|
|
Loc.tomo_sal_13.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.tomo_sal_12.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Space
|
|
Loc.space_miluchy.value : Rulesets(AccessRule.SHOOT, AccessRule.FLY),
|
|
Loc.space_freet.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.space_chico.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.space_sal_10.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.space_sal_11.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Bosses
|
|
Loc.boss_monkey_white.value : Rulesets(AccessRule.MORPH_NO_MONKEY),
|
|
Loc.boss_monkey_blue.value : Rulesets(AccessRule.ATTACK),
|
|
Loc.boss_monkey_yellow.value : Rulesets(AccessRule.NINJA),
|
|
Loc.boss_monkey_pink.value : Rulesets(AccessRule.MORPH_NO_MONKEY),
|
|
Loc.boss_monkey_red.value : Rulesets(AccessRule.MORPH_NO_MONKEY),
|
|
Loc.boss_specter.value : Rulesets([AccessRule.MORPH_NO_MONKEY, AccessRule.SHOOT]),
|
|
Loc.boss_specter_final.value : Rulesets([AccessRule.ATTACK, AccessRule.SWIM])
|
|
})
|
|
|
|
self.event_rules.update({
|
|
# Castle
|
|
Events.castle_b_clapper.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Ciscocity
|
|
Events.ciscocity_c_button.value : Rulesets(AccessRule.SHOOT, AccessRule.DASH, AccessRule.RCC),
|
|
|
|
# Studio
|
|
Events.studio_a1_button.value : Rulesets(AccessRule.ATTACK),
|
|
Events.studio_a2_button.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Halloween
|
|
Events.halloween_b_jumbo_robo.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Onsen
|
|
Events.onsen_a_button.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Snowfesta
|
|
Events.snowfesta_e_bell.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Edotown
|
|
Events.edotown_b1_button.value : Rulesets(AccessRule.ATTACK),
|
|
Events.edotown_e_scroll.value : Rulesets(AccessRule.CLUB, AccessRule.KNIGHT,
|
|
AccessRule.NINJA, AccessRule.MAGICIAN,
|
|
AccessRule.KUNGFU),
|
|
|
|
# Heaven
|
|
Events.heaven_b_clapper.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Iceland
|
|
Events.iceland_c_jumbo_robo.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Asia
|
|
Events.asia_b2_button.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Plane
|
|
Events.plane_d1_clapper.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Hong
|
|
Events.hong_b2_button.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Bay
|
|
Events.bay_a7_button.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Space
|
|
Events.space_g_button.value : Rulesets([AccessRule.SWIM, AccessRule.ATTACK]),
|
|
})
|
|
|
|
self.entrance_rules.update({
|
|
# Seaside
|
|
Stage.entrance_seaside_ab.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Woods
|
|
Stage.entrance_woods_bc.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Castle
|
|
Stage.entrance_castle_dd1.value : Rulesets(AccessRule.KNIGHT, AccessRule.SHOOT),
|
|
Stage.entrance_castle_d1d.value : Rulesets(AccessRule.KNIGHT, AccessRule.SHOOT),
|
|
Stage.entrance_castle_bb1.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Ciscocity
|
|
Stage.entrance_ciscocity_ab.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_ciscocity_ce.value : Rulesets([AccessRule.MONKEY, AccessRule.ATTACK]),
|
|
|
|
# Studio
|
|
Stage.entrance_studio_d1d.value : Rulesets(AccessRule.ATTACK, AccessRule.GLIDE),
|
|
Stage.entrance_studio_d2d.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Halloween
|
|
Stage.entrance_halloween_a1a.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_halloween_aa1.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_halloween_c1c.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_halloween_cc1.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_halloween_cc2.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_halloween_c2c.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_halloween_dd1.value : Rulesets(AccessRule.KNIGHT),
|
|
Stage.entrance_halloween_d1d.value : Rulesets(AccessRule.KNIGHT),
|
|
Stage.entrance_halloween_d1d2.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Western
|
|
Stage.entrance_western_bb1.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_western_fd2.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_western_dd2.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_western_d1d2.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_western_d2d.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_western_ed1.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Onsen
|
|
Stage.entrance_onsen_aa1.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_onsen_aa2.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_onsen_a1a2.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_onsen_a2a1.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_onsen_a1a1m.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_onsen_a2a2m.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_onsen_b1b.value : Rulesets([AccessRule.RCC, AccessRule.SWIM]),
|
|
Stage.entrance_onsen_bd1.value : Rulesets(AccessRule.SHOOT),
|
|
Stage.entrance_onsen_dd1.value : Rulesets(AccessRule.RCC),
|
|
|
|
# Edotown
|
|
Stage.entrance_edotown_a1a.value : Rulesets(AccessRule.NINJA),
|
|
Stage.entrance_edotown_aa1.value : Rulesets(AccessRule.NINJA),
|
|
Stage.entrance_edotown_ab1.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_edotown_b1a.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_edotown_b2b1.value : Rulesets([event_invoked(Events.edotown_b1_button.value),
|
|
AccessRule.NINJA], AccessRule.SWIM),
|
|
Stage.entrance_edotown_b2b.value : Rulesets(AccessRule.NINJA),
|
|
Stage.entrance_edotown_bb2.value : Rulesets(AccessRule.NINJA),
|
|
Stage.entrance_edotown_bc1.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_edotown_c1c.value : Rulesets(AccessRule.NINJA),
|
|
Stage.entrance_edotown_cc1.value : Rulesets(AccessRule.NINJA),
|
|
Stage.entrance_edotown_cc2.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Heaven
|
|
Stage.entrance_heaven_a1a.value : Rulesets(AccessRule.FLY),
|
|
Stage.entrance_heaven_aa1.value : Rulesets(AccessRule.FLY),
|
|
Stage.entrance_heaven_ab.value : Rulesets(AccessRule.NINJA, AccessRule.HERO, [AccessRule.FLYER,
|
|
AccessRule.HOOP]),
|
|
Stage.entrance_heaven_bb1.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Toyhouse
|
|
Stage.entrance_toyhouse_bb1.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_toyhouse_ef.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_toyhouse_fe.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_toyhouse_fa.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Iceland
|
|
Stage.entrance_iceland_a1a.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_iceland_aa2.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_iceland_a2a.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_iceland_be.value : Rulesets(AccessRule.DASH),
|
|
|
|
# Asia
|
|
Stage.entrance_asia_ab.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_ba.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_a1a.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_a1b2.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_a1a3.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_a2a1.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_a2a3.value : Rulesets([event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value)]),
|
|
Stage.entrance_asia_a2a4.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_a3a1.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_a3a4.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_a3a2.value : Rulesets([event_invoked(Events.asia_a_block.value),
|
|
event_invoked(Events.asia_a1_block.value),
|
|
event_invoked(Events.asia_a2_block.value)]),
|
|
Stage.entrance_asia_a4a3.value : Rulesets(AccessRule.SWIM),
|
|
Stage.entrance_asia_a4d1.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_asia_b2b.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_asia_dd1.value : Rulesets([AccessRule.SWIM, AccessRule.FLY]),
|
|
Stage.entrance_asia_ee1.value : Rulesets([AccessRule.ATTACK, AccessRule.DASH, AccessRule.RCC]),
|
|
|
|
# Plane
|
|
Stage.entrance_plane_dd1.value : Rulesets(AccessRule.FLY),
|
|
Stage.entrance_plane_d1d.value : Rulesets(AccessRule.FLY),
|
|
Stage.entrance_plane_d1e.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Hong
|
|
Stage.entrance_hong_aa1.value : Rulesets(AccessRule.KUNGFU),
|
|
Stage.entrance_hong_a1a2.value : Rulesets(AccessRule.ATTACK),
|
|
Stage.entrance_hong_cc1.value : Rulesets([AccessRule.ATTACK, AccessRule.GLIDE]),
|
|
Stage.entrance_hong_c1c.value : Rulesets([AccessRule.ATTACK, AccessRule.GLIDE]),
|
|
|
|
# Bay
|
|
Stage.entrance_bay_aa1.value : Rulesets([AccessRule.ATTACK, AccessRule.SHOOT, AccessRule.SWIM]),
|
|
Stage.entrance_bay_a1a.value : Rulesets([AccessRule.ATTACK, AccessRule.SWIM]),
|
|
Stage.entrance_bay_a3a4.value : Rulesets(AccessRule.RCC),
|
|
Stage.entrance_bay_cc1.value : Rulesets([AccessRule.ATTACK, AccessRule.FLY]),
|
|
Stage.entrance_bay_e1e2.value : Rulesets(AccessRule.ATTACK),
|
|
|
|
# Tomo
|
|
Stage.entrance_tomo_bc.value : Rulesets(AccessRule.GLIDE),
|
|
|
|
# Space
|
|
Stage.entrance_space_ff1.value : Rulesets(AccessRule.GLIDE),
|
|
Stage.entrance_space_gg1.value : Rulesets([AccessRule.SWIM, AccessRule.ATTACK]),
|
|
})
|
|
|
|
LogicPreferenceOptions : list = [
|
|
Casual,
|
|
Normal,
|
|
Hard,
|
|
Expert
|
|
]
|
|
|
|
# [<--- SHOP ITEMS RULES HANDLING --->]
|
|
@dataclass
|
|
class ShopItemRules:
|
|
item_rules : dict[str, Rulesets]
|
|
entrances : list[AE3EntranceMeta]
|
|
entrance_rules : dict[str, Rulesets]
|
|
post_game_items: set[str]
|
|
post_game_entrances: set[str]
|
|
blacklisted_items: set[str]
|
|
blacklisted_entrances : list[str]
|
|
blacklisted_stages : list[str]
|
|
cheap_early_items : list[str]
|
|
|
|
sets : int = 0
|
|
|
|
def __init__(self, world : "AE3World"):
|
|
self.item_rules = {}
|
|
self.entrances = []
|
|
self.entrance_rules = {}
|
|
self.post_game_items = set()
|
|
self.post_game_entrances = set()
|
|
self.blacklisted_items = set()
|
|
self.blacklisted_entrances = [*ENTRANCES_SHOP_PROGRESSION]
|
|
self.blacklisted_stages = [*STAGES_SHOP_PROGRESSION]
|
|
self.cheap_early_items = []
|
|
|
|
self.sets = 0
|
|
|
|
if not world.options.shoppingsanity:
|
|
return
|
|
|
|
# If farmable areas are not available before Post Game, and Cheap Items have a minimum requirement of PGC,
|
|
# All Shop Items will only be in logic after Post Game is unlocked.
|
|
# This also removes any Shop Item from being a requirement for PGC
|
|
are_farmables_available: bool = ShopItemRules.are_farmables_available(world)
|
|
if not are_farmables_available and world.options.cheap_items_minimum_requirement >= 100:
|
|
self.post_game_entrances.add(Stage.entrance_travel_ab.value)
|
|
self.post_game_items.update(SHOP_PERSISTENT_MASTER)
|
|
|
|
if world.options.shoppingsanity == 2:
|
|
self.post_game_items.update(SHOP_COLLECTION_MASTER)
|
|
else:
|
|
self.post_game_items.update(SHOP_UNIQUE_MASTER)
|
|
|
|
if world.options.shoppingsanity >= 3:
|
|
self.blacklisted_entrances = []
|
|
self.blacklisted_stages = []
|
|
|
|
return
|
|
|
|
# Post Game Properties
|
|
required_keys : int = len(world.progression.progression) - 3
|
|
can_farm : list[Rulesets] = [AccessRule.FARM]
|
|
|
|
if world.options.farm_logic_sneaky_borgs.value:
|
|
can_farm.append(AccessRule.FARM_DUPE)
|
|
|
|
self.item_rules = {
|
|
Loc.hint_book_9.value: Rulesets(can_access_region(Stage.region_heaven_a.value)),
|
|
Loc.hint_book_14.value: Rulesets(can_access_region(Stage.region_boss1.value)),
|
|
Loc.hint_book_15.value: Rulesets(can_access_region(Stage.region_boss2.value)),
|
|
Loc.hint_book_16.value: Rulesets(can_access_region(Stage.region_boss3.value)),
|
|
Loc.hint_book_17.value: Rulesets(can_access_region(Stage.region_boss4.value)),
|
|
Loc.hint_book_18.value: Rulesets(can_access_region(Stage.region_boss5.value)),
|
|
Loc.hint_book_19.value: Rulesets(can_access_region(Stage.region_boss6.value)),
|
|
Loc.hint_book_20.value: Rulesets(can_access_region(Stage.region_specter1.value)),
|
|
|
|
Loc.movie_tape_17.value: Rulesets(can_access_region(Stage.region_tomo_a.value)),
|
|
Loc.movie_tape_26.value: Rulesets(can_access_region(Stage.region_specter2.value)),
|
|
Loc.movie_tape_27.value: Rulesets(can_access_region(Stage.region_specter2.value)),
|
|
Loc.music_disc_41.value: Rulesets(can_access_region(Stage.region_specter2.value)),
|
|
}
|
|
|
|
self.post_game_items.add(Loc.shop_ultim_ape_fighter.value)
|
|
|
|
self.entrance_rules = {
|
|
Stage.entrance_shop_expensive.value : Rulesets(*can_farm),
|
|
Stage.entrance_shop_morph.value : Rulesets(AccessRule.MORPH),
|
|
}
|
|
|
|
if world.options.shoppingsanity.value <= 1:
|
|
return
|
|
|
|
post_game_start_index: int = sum(world.progression.progression[:-1])
|
|
post_game_end_index: int = post_game_start_index + world.progression.progression[-2]
|
|
post_game_channels: list[str] = [LEVELS_BY_ORDER[channel] for channel in
|
|
world.progression.order[post_game_start_index:post_game_end_index]]
|
|
post_game_areas: list[str] = []
|
|
for channel in post_game_channels:
|
|
post_game_areas.extend(STAGES_DIRECTORY_LABEL[channel])
|
|
|
|
for channel, items in SHOP_EVENT_ACCESS_DIRECTORY.items():
|
|
if channel in post_game_areas:
|
|
self.post_game_items.update(items)
|
|
|
|
cheap_items_early_amount: int = world.options.cheap_items_early_amount.value
|
|
|
|
if world.options.cheap_items_minimum_requirement:
|
|
self.entrance_rules[Stage.entrance_travel_ab.value] = Rulesets(*can_farm)
|
|
cheap_items_early_amount = 0
|
|
|
|
if world.options.cheap_items_minimum_requirement.value < 100:
|
|
cheap_items_rule = has_keys(math.ceil(
|
|
required_keys * (world.options.cheap_items_minimum_requirement.value / 100)))
|
|
|
|
self.entrance_rules[Stage.entrance_travel_ab.value].update(Rulesets(cheap_items_rule))
|
|
else:
|
|
if world.options.shoppingsanity.value != 2:
|
|
self.post_game_items.update(SHOP_CHEAP_MASTER)
|
|
else:
|
|
self.post_game_items.update(SHOP_CHEAP_COLLECTION_MASTER)
|
|
|
|
if world.options.shoppingsanity.value == 2:
|
|
if cheap_items_early_amount:
|
|
for category in SHOP_CHEAP_COLLECTION_INDEX:
|
|
self.cheap_early_items.extend(category[:cheap_items_early_amount])
|
|
|
|
return
|
|
# Progression Splitting Properties
|
|
elif world.options.shoppingsanity.value == 3:
|
|
self.sets = math.ceil(28 / (required_keys + 2))
|
|
reached_shop_progress = lambda amount : has_keys(amount)
|
|
|
|
self.blacklisted_entrances.clear()
|
|
self.blacklisted_stages.clear()
|
|
else:
|
|
self.sets : int = math.ceil(28 / world.options.restock_progression.value)
|
|
reached_shop_progress = lambda amount: has_shop_stock(amount)
|
|
|
|
self.blacklisted_entrances.clear()
|
|
self.blacklisted_stages.clear()
|
|
|
|
enough_cheap_items : bool = False
|
|
for i, entrance in enumerate(ENTRANCES_SHOP_PSEUDOREGIONS):
|
|
current_set = math.floor(i / self.sets)
|
|
if world.options.shoppingsanity.value == 3 and current_set * self.sets + self.sets >= 27:
|
|
self.post_game_entrances.add(entrance.name)
|
|
if math.floor(current_set / self.sets) > 0:
|
|
self.entrance_rules[entrance.name] = Rulesets(reached_shop_progress(math.floor(i / self.sets)))
|
|
|
|
if cheap_items_early_amount and not enough_cheap_items:
|
|
cheap : list[str] = [item for item in SHOP_PROGRESSION_DIRECTORY[entrance.destination]
|
|
if item in SHOP_CHEAP_MASTER]
|
|
expensive : list[str] = [item for item in SHOP_PROGRESSION_DIRECTORY[entrance.destination]
|
|
if item not in SHOP_CHEAP_MASTER]
|
|
|
|
if len(self.cheap_early_items) + len(cheap) <= cheap_items_early_amount:
|
|
self.cheap_early_items.extend(cheap)
|
|
|
|
if are_farmables_available:
|
|
for items in expensive:
|
|
self.item_rules[items] = Rulesets(*can_farm)
|
|
else:
|
|
self.post_game_items.update(expensive)
|
|
|
|
self.entrances.append(AE3EntranceMeta(entrance.name, Stage.travel_station_b.value,
|
|
entrance.destination))
|
|
else:
|
|
enough_cheap_items = True
|
|
self.entrances.append(AE3EntranceMeta(entrance.name, Stage.region_shop_expensive.value,
|
|
entrance.destination))
|
|
else:
|
|
self.entrances.append(AE3EntranceMeta(entrance.name, Stage.region_shop_expensive.value,
|
|
entrance.destination))
|
|
|
|
def set_pgc_rules(self, world : "AE3World") -> None:
|
|
if not world.options.shoppingsanity.value: return
|
|
|
|
required_keys:int = len(world.progression.progression) - 3
|
|
post_game_condition_rule:Callable[[CollectionState, int], bool] = world.post_game_condition.enact(
|
|
required_keys - 1, world.options.monkeysanity_break_rooms.value)
|
|
|
|
self.item_rules[Loc.shop_ultim_ape_fighter.value] = Rulesets(post_game_condition_rule)
|
|
|
|
if world.options.cheap_items_minimum_requirement.value >= 100:
|
|
self.entrance_rules.setdefault(
|
|
Stage.entrance_travel_ab.value, Rulesets()).update(Rulesets(post_game_condition_rule))
|
|
|
|
for item in self.post_game_items:
|
|
self.item_rules[item] = Rulesets(post_game_condition_rule)
|
|
|
|
for entrance in self.post_game_entrances:
|
|
self.entrance_rules[entrance] = Rulesets(post_game_condition_rule)
|
|
|
|
@staticmethod
|
|
def are_farmables_available(world: 'AE3World') -> bool:
|
|
if not world.options.shoppingsanity.value: return True
|
|
|
|
farming_areas: list[str] = [*STAGES_FARMABLE]
|
|
if world.options.farm_logic_sneaky_borgs:
|
|
farming_areas.extend([*STAGES_FARMABLE_SNEAKY_BORG])
|
|
|
|
post_game_start_index: int = sum(world.progression.progression[:-1])
|
|
post_game_end_index: int = post_game_start_index + world.progression.progression[-2]
|
|
post_game_channels: list[str] = [LEVELS_BY_ORDER[channel] for channel in
|
|
world.progression.order[post_game_start_index:post_game_end_index]]
|
|
post_game_areas: list[str] = []
|
|
for channel in post_game_channels:
|
|
post_game_areas.extend(STAGES_DIRECTORY_LABEL[channel])
|
|
|
|
return any(stage not in post_game_areas for stage in farming_areas)
|
|
|
|
# [<--- GOAL TARGETS --->]
|
|
class Specter(GoalTarget):
|
|
name = "Specter"
|
|
description = "Capture Specter by clearing \"Specter Battle!\""
|
|
|
|
locations = {Loc.boss_specter.value}
|
|
|
|
|
|
class SpecterFinal(Specter):
|
|
name = "Specter Final"
|
|
description = "Capture Specter by clearing \"Specter's Final Battle!\""
|
|
|
|
locations = {Loc.boss_specter_final.value}
|
|
|
|
|
|
class TripleThreat(GoalTarget):
|
|
name = "Triple Threat"
|
|
description = "Defeat at least 3 bosses!"
|
|
|
|
locations = {*MONKEYS_BOSSES}
|
|
|
|
amount = 3
|
|
|
|
|
|
class PlaySpike(GoalTarget):
|
|
name = "Play Spike"
|
|
description = "Go and Capture 204 Pipo Monkeys!"
|
|
|
|
locations = {monkey for monkey in MONKEYS_MASTER if monkey != Loc.boss_tomoki.value and monkey not in
|
|
MONKEYS_PASSWORDS}
|
|
|
|
amount = 204
|
|
|
|
def verify(self, state: CollectionState, player: int) -> bool:
|
|
minimum_equipment : list[Callable] = [AccessRule.DASH, AccessRule.SWIM, AccessRule.SLING, AccessRule.RCC,
|
|
AccessRule.MAGICIAN, AccessRule.KUNGFU, AccessRule.HERO]
|
|
|
|
if any(monkey in MONKEYS_BREAK_ROOMS for monkey in self.locations):
|
|
minimum_equipment.append(AccessRule.MONKEY)
|
|
|
|
for rule in minimum_equipment:
|
|
if not rule(state, player):
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
class PlayJimmy(PlaySpike):
|
|
name = "Play Jimmy"
|
|
description = "Go and Capture 300 Pipo Monkeys!"
|
|
|
|
amount = 300
|
|
|
|
|
|
class DirectorsCut(GoalTarget):
|
|
name = "Director's Cut"
|
|
description = "Capture all Monkey Films across all the channels!"
|
|
|
|
locations = {*CAMERAS_MASTER}
|
|
|
|
|
|
class PhoneCheck(DirectorsCut):
|
|
name = "Phone Check"
|
|
description = "Activate all Cellphones scattered across the channels!"
|
|
|
|
locations = {*Cellphone_Name_to_ID.values()}
|
|
|
|
class ShopCollector(GoalTarget):
|
|
name = "Shop Collector"
|
|
description = "Buy all of the Shop Items in the Shopping Area!"
|
|
|
|
locations = {*LOCATIONS_DIRECTORY[APHelper.shop.value]}
|
|
amount = len(SHOP_UNIQUE_MASTER)
|
|
|
|
|
|
class PasswordHunt(DirectorsCut):
|
|
name = "Password Hunt"
|
|
|
|
locations = {*MONKEYS_PASSWORDS}
|
|
|
|
|
|
GoalTargetOptions : list[Callable] = [
|
|
Specter, SpecterFinal, TripleThreat, PlaySpike, PlayJimmy, DirectorsCut, PhoneCheck, ShopCollector
|
|
] |