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
170 lines
7.6 KiB
Python
170 lines
7.6 KiB
Python
from typing import Set, cast
|
|
|
|
from .RulesData import location_rules
|
|
from .RulesData import connection_rules
|
|
from .Items import OriBlindForestItem, item_dict
|
|
from .Locations import OriBlindForestLocation, tagged_locations_dict, event_location_list
|
|
from .Options import OriBlindForestOptions, MapstoneLogic
|
|
from BaseClasses import CollectionState, Location, Entrance, ItemClassification, Region
|
|
from ..AutoWorld import World
|
|
from ..generic.Rules import add_rule, set_rule
|
|
|
|
|
|
def apply_location_rules(world: World):
|
|
# for each region in location rules, and for each location
|
|
# create a location and call process_access_point
|
|
for region_name, locations in location_rules.items():
|
|
region = world.get_region(region_name)
|
|
valid_location_ids: dict[str, int | None] = get_location_ids(world, list(locations.keys()))
|
|
region.add_locations(valid_location_ids, OriBlindForestLocation)
|
|
|
|
for location, rulesets in locations.items():
|
|
if location in valid_location_ids.keys():
|
|
process_access_point(world, world.get_location(location), rulesets)
|
|
|
|
|
|
def get_location_ids(world: World, locations: list[str]) -> dict[str, int | None]:
|
|
# get the ids for each location in the list as long as they aren't excluded
|
|
# if the location is an event, create it with a None id
|
|
# otherwise add its id from the name_to_id list
|
|
ids: dict[str, int | None] = {}
|
|
for location in locations:
|
|
if location not in world.location_exclusion_list:
|
|
if location in event_location_list:
|
|
ids[location] = None
|
|
else:
|
|
ids[location] = world.location_name_to_id[location]
|
|
|
|
return ids
|
|
|
|
|
|
def apply_connection_rules(world: World):
|
|
# for each region in connection rules, and for each connecting region,
|
|
# create an entrance and call process_access_point
|
|
for region_name, connections in connection_rules.items():
|
|
region = world.get_region(region_name)
|
|
id = 1
|
|
for connection, rulesets in connections.items():
|
|
entrance_name = region_name + "_to_" + connection + "_" + str(id)
|
|
id += 1
|
|
region.connect(world.get_region(connection), entrance_name)
|
|
access_point = world.get_entrance(entrance_name)
|
|
process_access_point(world, access_point, rulesets)
|
|
|
|
|
|
def process_access_point(world: World, access_point: Location | Entrance, rulesets: dict[str, list[list[str | tuple[str, int]]]]):
|
|
# preface with a false so all other rules can be combined with OR
|
|
set_rule(access_point, lambda state: False)
|
|
|
|
# for each ruleset in the location/entrance, call process_ruleset
|
|
for ruleset_name, ruleset in rulesets.items():
|
|
if ruleset_name in world.logic_sets:
|
|
process_ruleset(world, access_point, ruleset)
|
|
|
|
|
|
def process_ruleset(world: World, access_point: Location | Entrance, ruleset: list[list[str | tuple[str, int]]]):
|
|
# for each access set in the ruleset, call process_access_set
|
|
for access_set in ruleset:
|
|
process_access_set(world, access_point, access_set)
|
|
|
|
def process_access_set(world: World, access_point: Location | Entrance, access_set: list[str | tuple[str, int]]):
|
|
# add the rule for the access set list using oribf_has
|
|
# this line needs to be in a separate function from the previous for loop in order to work properly
|
|
# (likely lambda function strangeness)
|
|
add_rule(access_point, lambda state: all(oribf_has(world, state, item) for item in access_set), "or")
|
|
|
|
|
|
def oribf_has(world: World, state: CollectionState, item: str | tuple[str, int]) -> bool:
|
|
options: OriBlindForestOptions = cast(OriBlindForestOptions, world.options)
|
|
|
|
if type(item) == str:
|
|
if item in item_dict.keys():
|
|
# handles normal abilities like Dash, Climb, Wind, etc.
|
|
return state.has(item, world.player)
|
|
|
|
elif item == "Free":
|
|
return True
|
|
|
|
elif item == "Lure":
|
|
return options.enable_lure == True
|
|
|
|
elif item == "DoubleBash":
|
|
return options.enable_double_bash == True and state.has("Bash", world.player)
|
|
|
|
elif item == "GrenadeJump":
|
|
return options.enable_grenade_jump == True and state.has_all(["Climb", "ChargeJump", "Grenade"], world.player)
|
|
|
|
elif item == "ChargeFlameBurn":
|
|
return options.enable_charge_flame_burn == True and \
|
|
state.has("ChargeFlame", world.player) and state.has("AbilityCell", world.player, 3)
|
|
|
|
elif item in ["ChargeDash", "RocketJump"]:
|
|
return options.enable_charge_dash == True and \
|
|
state.has("Dash", world.player) and state.has("AbilityCell", world.player, 6)
|
|
|
|
elif item == "AirDash":
|
|
return options.enable_air_dash == True and \
|
|
state.has("Dash", world.player) and state.has("AbilityCell", world.player, 3)
|
|
|
|
elif item == "TripleJump":
|
|
return options.enable_triple_jump == True and \
|
|
state.has("DoubleJump", world.player) and state.has("AbilityCell", world.player, 12)
|
|
|
|
elif item == "UltraDefense":
|
|
return options.enable_damage_boost == True and state.has("AbilityCell", world.player, 12)
|
|
|
|
elif item == "BashGrenade":
|
|
return state.has_all(["Bash", "Grenade"], world.player)
|
|
|
|
elif item == "Rekindle":
|
|
return options.enable_rekindle == True
|
|
|
|
elif item == "Open":
|
|
# closed dungeons not implemented
|
|
return True
|
|
|
|
elif item == "OpenWorld":
|
|
# open world not implemented yet
|
|
return False
|
|
else:
|
|
return False
|
|
else:
|
|
# if item isnt a string its a tuple (check for number of health, keystones, etc.)
|
|
# if item is a health cell, only add it if damage boost is enabled
|
|
if (item[0] == "HealthCell" and options.enable_damage_boost == True) or item[0] != "HealthCell":
|
|
return state.has(item[0], world.player, int(item[1]))
|
|
|
|
return False
|
|
|
|
|
|
def oribf_has_all(state: CollectionState, items: Set[str], player: int) -> bool:
|
|
return all(state.has(item, player) if type(item) == str else state.has(item[0], player, int(item[1]))
|
|
for item in items)
|
|
|
|
|
|
def create_progressive_maps(world: World):
|
|
# place the locked items in the events that were created before
|
|
for event in event_location_list:
|
|
world.get_location(event).place_locked_item(OriBlindForestItem(event, ItemClassification.progression, None, world.player))
|
|
|
|
# create the progressive map locations
|
|
menu_region: Region = world.get_region("Menu")
|
|
menu_region.add_locations({location: world.location_name_to_id[location] for location in tagged_locations_dict["ProgressiveMap"]}, \
|
|
OriBlindForestLocation)
|
|
|
|
for location_name in tagged_locations_dict["ProgressiveMap"]:
|
|
location: Location = world.get_location(location_name)
|
|
amount: int = int(location_name[-1])
|
|
set_progressive_mapstone_rule(world, location, amount)
|
|
|
|
def set_progressive_mapstone_rule(world: World, location: Location, amount: int):
|
|
set_rule(location, lambda state: (at_least([state.can_reach_location(map_event, world.player) \
|
|
for map_event in event_location_list], amount=amount)) and \
|
|
state.has("MapStone", world.player, count=amount))
|
|
|
|
def at_least(conditions: list[bool], amount: int) -> bool:
|
|
count: int = 0
|
|
for flag in conditions:
|
|
if flag:
|
|
count += 1
|
|
return count >= amount |