mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-22 07:35:37 -07:00
progrees i think
This commit is contained in:
@@ -52,7 +52,8 @@ class TestBase(unittest.TestCase):
|
||||
state = multiworld.get_all_state(False)
|
||||
for location in multiworld.get_locations():
|
||||
with self.subTest("Location should be reached", location=location.name):
|
||||
self.assertTrue(location.can_reach(state), f"{location.name} unreachable")
|
||||
if not location.can_reach(state):
|
||||
self.assertTrue(location.can_reach(state), f"{location.name} unreachable")
|
||||
|
||||
for region in multiworld.get_regions():
|
||||
if region.name in unreachable_regions:
|
||||
|
||||
79
worlds/satisfactory/CriticalPathCalculator.py
Normal file
79
worlds/satisfactory/CriticalPathCalculator.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from random import Random
|
||||
from typing import Set, Tuple
|
||||
from .GameLogic import GameLogic, Recipe
|
||||
from .Options import SatisfactoryOptions
|
||||
from .Options import SatisfactoryOptions
|
||||
|
||||
class CriticalPathCalculator:
|
||||
logic: GameLogic
|
||||
random: Random
|
||||
|
||||
potential_required_parts: Set[str]
|
||||
potential_required_buildings: Set[str]
|
||||
potential_required_belt_speed: int
|
||||
potential_required_pipes: bool
|
||||
potential_required_radioactive: bool
|
||||
potential_required_power: int
|
||||
potential_required_recipes_names: Set[str]
|
||||
|
||||
def __init__(self, logic: GameLogic, random: Random, options: SatisfactoryOptions):
|
||||
self.logic = logic
|
||||
self.random = random
|
||||
|
||||
self.potential_required_parts = set()
|
||||
self.potential_required_buildings = set()
|
||||
self.potential_required_belt_speed = 1
|
||||
self.potential_required_pipes = False
|
||||
self.potential_required_radioactive = False
|
||||
self.potential_required_power: int = 1
|
||||
|
||||
self.select_minimal_required_parts_for(
|
||||
tuple(self.logic.space_elevator_tiers[options.final_elevator_package - 1].keys())
|
||||
)
|
||||
for i in range(self.potential_required_belt_speed, 1):
|
||||
self.select_minimal_required_parts_for(self.logic.buildings[f"Conveyor Mk.{i}"].inputs)
|
||||
if self.potential_required_pipes:
|
||||
self.select_minimal_required_parts_for(self.logic.buildings["Pipeline Pump Mk.1"].inputs)
|
||||
self.select_minimal_required_parts_for(self.logic.buildings["Pipeline Pump Mk.2"].inputs)
|
||||
if self.potential_required_radioactive:
|
||||
self.select_minimal_required_parts_for(self.logic.recipes["Hazmat Suit"][0].inputs)
|
||||
self.select_minimal_required_parts_for(self.logic.recipes["Iodine Infused Filter"][0].inputs)
|
||||
for i in range(self.potential_required_belt_speed, 1):
|
||||
power_recipe = random.choice(self.logic.requirement_per_powerlevel[i])
|
||||
self.select_minimal_required_parts_for(power_recipe.inputs)
|
||||
self.potential_required_buildings.add(power_recipe.building)
|
||||
|
||||
|
||||
self.potential_required_recipes_names = set(
|
||||
recipe.name
|
||||
for part in self.potential_required_parts
|
||||
for recipe in self.logic.recipes[part]
|
||||
)
|
||||
self.potential_required_recipes_names.update(
|
||||
"Building: "+ building
|
||||
for building in self.potential_required_buildings
|
||||
)
|
||||
|
||||
debug = True
|
||||
|
||||
|
||||
def select_minimal_required_parts_for(self, parts: Tuple[str]) -> None:
|
||||
if parts:
|
||||
for part in parts:
|
||||
if part in self.potential_required_parts:
|
||||
continue
|
||||
|
||||
self.potential_required_parts.add(part)
|
||||
|
||||
for recipe in self.logic.recipes[part]:
|
||||
self.potential_required_belt_speed = \
|
||||
max(self.potential_required_belt_speed, recipe.minimal_belt_speed)
|
||||
|
||||
self.select_minimal_required_parts_for(recipe.inputs)
|
||||
self.select_minimal_required_parts_for(self.logic.buildings[recipe.building].inputs)
|
||||
|
||||
self.potential_required_buildings.add(recipe.building)
|
||||
|
||||
if self.logic.buildings[recipe.building].power_requirement:
|
||||
self.potential_required_power = \
|
||||
max(self.potential_required_power, self.logic.buildings[recipe.building].power_requirement)
|
||||
@@ -572,8 +572,6 @@ class GameLogic:
|
||||
Recipe("AI Expansion Server", "Quantum Encoder", ("Dark Matter Residue", "Excited Photonic Matter", "Magnetic Field Generator", "Neural-Quantum Processor", "Superposition Oscillator")), ),
|
||||
###
|
||||
#1.0
|
||||
|
||||
# TODO transport types aren't currently in logic
|
||||
}
|
||||
|
||||
buildings: Dict[str, Building] = {
|
||||
|
||||
@@ -1,40 +1,42 @@
|
||||
from enum import Enum
|
||||
from enum import IntFlag
|
||||
from typing import NamedTuple, Set
|
||||
from BaseClasses import ItemClassification
|
||||
|
||||
class ItemGroups(str, Enum):
|
||||
Parts = 1
|
||||
Equipment = 2
|
||||
Ammo = 3
|
||||
Recipe = 4
|
||||
Building = 5
|
||||
Trap = 6
|
||||
Lights = 7
|
||||
Foundations = 8
|
||||
Transport = 9
|
||||
Trains = 10
|
||||
ConveyorMk1 = 11
|
||||
ConveyorMk2 = 12
|
||||
ConveyorMk3 = 13
|
||||
ConveyorMk4 = 14
|
||||
ConveyorMk5 = 15
|
||||
ConveyorSupports = 16
|
||||
PipesMk1 = 17
|
||||
PipesMk2 = 18
|
||||
PipelineSupports = 19
|
||||
HyperTubes = 20
|
||||
Signs = 21
|
||||
Pilars = 22
|
||||
Beams = 23
|
||||
Walls = 24
|
||||
Upgrades = 25
|
||||
Vehicles = 26
|
||||
Customizer = 27
|
||||
ConveyorMk6 = 28
|
||||
class ItemGroups(IntFlag):
|
||||
Parts = 1 << 1
|
||||
Equipment = 1 << 2
|
||||
Ammo = 1 << 3
|
||||
Recipe = 1 << 4
|
||||
Building = 1 << 5
|
||||
Trap = 1 << 6
|
||||
Lights = 1 << 7
|
||||
Foundations = 1 << 8
|
||||
Transport = 1 << 9
|
||||
Trains = 1 << 10
|
||||
ConveyorMk1 = 1 << 11
|
||||
ConveyorMk2 = 1 << 12
|
||||
ConveyorMk3 = 1 << 13
|
||||
ConveyorMk4 = 1 << 14
|
||||
ConveyorMk5 = 1 << 15
|
||||
ConveyorSupports = 1 << 16
|
||||
PipesMk1 = 1 << 17
|
||||
PipesMk2 = 1 << 18
|
||||
PipelineSupports = 1 << 19
|
||||
HyperTubes = 1 << 20
|
||||
Signs = 1 << 21
|
||||
Pilars = 1 << 22
|
||||
Beams = 1 << 23
|
||||
Walls = 1 << 24
|
||||
Upgrades = 1 << 25
|
||||
Vehicles = 1 << 26
|
||||
Customizer = 1 << 27
|
||||
ConveyorMk6 = 1 << 28
|
||||
BasicNeeds = 1 << 29
|
||||
|
||||
|
||||
class ItemData(NamedTuple):
|
||||
"""Represents an item in the pool, it could be a resource bundle, production recipe, trap, etc."""
|
||||
category: Set[ItemGroups]
|
||||
category: ItemGroups
|
||||
code: int
|
||||
type: ItemClassification = ItemClassification.filler
|
||||
count: int = 1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@ from .GameLogic import GameLogic, Recipe, Building, PowerInfrastructureLevel, Dr
|
||||
from .StateLogic import StateLogic, EventId, part_event_prefix, building_event_prefix
|
||||
from .Items import Items
|
||||
from .Options import SatisfactoryOptions
|
||||
from .CriticalPathCalculator import CriticalPathCalculator
|
||||
from math import ceil, floor
|
||||
|
||||
|
||||
@@ -43,9 +44,6 @@ class Part(LocationData):
|
||||
def can_produce_any_recipe_for_part(self, state_logic: StateLogic, recipes: Iterable[Recipe],
|
||||
name: str, items: Items) -> Callable[[CollectionState], bool]:
|
||||
def can_build_by_any_recipe(state: CollectionState) -> bool:
|
||||
if name == "Steel Ingot":
|
||||
debug = True
|
||||
|
||||
if items.precalculated_progression_recipes and name in items.precalculated_progression_recipes:
|
||||
can_produce: bool = state_logic.can_produce_specific_recipe_for_part(
|
||||
state, items.precalculated_progression_recipes[name])
|
||||
@@ -76,9 +74,6 @@ class EventBuilding(LocationData):
|
||||
) -> Callable[[CollectionState], bool]:
|
||||
|
||||
def can_build(state: CollectionState) -> bool:
|
||||
if building.name == "Building: Foundry":
|
||||
debug = True
|
||||
|
||||
return state_logic.has_recipe(state, building) \
|
||||
and state_logic.can_power(state, building.power_requirement) \
|
||||
and state_logic.can_produce_all_allowing_handcrafting(state, game_logic, building.inputs)
|
||||
@@ -177,6 +172,7 @@ class Locations():
|
||||
options: Optional[SatisfactoryOptions]
|
||||
state_logic: Optional[StateLogic]
|
||||
items: Optional[Items]
|
||||
critical_path: Optional[CriticalPathCalculator]
|
||||
|
||||
hub_location_start: ClassVar[int] = 1338000
|
||||
max_tiers: ClassVar[int] = 10
|
||||
@@ -186,11 +182,13 @@ class Locations():
|
||||
drop_pod_location_id_end: ClassVar[int] = 1338699
|
||||
|
||||
def __init__(self, game_logic: Optional[GameLogic] = None, options: Optional[SatisfactoryOptions] = None,
|
||||
state_logic: Optional[StateLogic] = None, items: Optional[Items] = None):
|
||||
state_logic: Optional[StateLogic] = None, items: Optional[Items] = None,
|
||||
critical_path: Optional[CriticalPathCalculator] = None):
|
||||
self.game_logic = game_logic
|
||||
self.options = options
|
||||
self.state_logic = state_logic
|
||||
self.items = items
|
||||
self.critical_path = critical_path
|
||||
|
||||
def get_base_location_table(self) -> List[LocationData]:
|
||||
return [
|
||||
@@ -310,8 +308,8 @@ class Locations():
|
||||
"Must include all possible location names and their id's"
|
||||
|
||||
location_table = self.get_base_location_table()
|
||||
location_table.extend(self.get_hub_locations())
|
||||
location_table.extend(self.get_drop_pod_locations())
|
||||
location_table.extend(self.get_hub_locations(True, self.max_tiers))
|
||||
location_table.extend(self.get_drop_pod_locations(True, self.max_tiers))
|
||||
location_table.append(LocationData("Overworld", "UpperBound", 1338999))
|
||||
|
||||
return {location.name: location.code for location in location_table}
|
||||
@@ -322,26 +320,38 @@ class Locations():
|
||||
if not self.game_logic or not self.options or not self.state_logic or not self.items:
|
||||
raise Exception("Locations need to be initialized with logic, options and items before using this method")
|
||||
|
||||
max_tier_for_game = min(self.options.final_elevator_package * 2, len(self.game_logic.hub_layout))
|
||||
|
||||
location_table = self.get_base_location_table()
|
||||
location_table.extend(self.get_hub_locations())
|
||||
location_table.extend(self.get_drop_pod_locations())
|
||||
location_table.extend(self.get_hub_locations(False, max_tier_for_game))
|
||||
location_table.extend(self.get_drop_pod_locations(False, max_tier_for_game))
|
||||
location_table.extend(self.get_logical_event_locations())
|
||||
|
||||
return location_table
|
||||
|
||||
def get_hub_locations(self) -> List[LocationData]:
|
||||
def get_hub_locations(self, for_data_package: bool, max_tier: int) -> List[LocationData]:
|
||||
location_table: List[LocationData] = []
|
||||
|
||||
number_of_slots_per_milestone_for_game: int
|
||||
if (for_data_package):
|
||||
number_of_slots_per_milestone_for_game = self.max_slots
|
||||
else:
|
||||
if self.options.final_elevator_package <= 2:
|
||||
number_of_slots_per_milestone_for_game = 10
|
||||
else:
|
||||
number_of_slots_per_milestone_for_game = self.game_logic.slots_per_milestone
|
||||
|
||||
hub_location_id = self.hub_location_start
|
||||
for tier in range(1, self.max_tiers + 1):
|
||||
for milestone in range(1, self.max_milestones + 1):
|
||||
for slot in range(1, self.max_slots + 1):
|
||||
if not self.game_logic:
|
||||
for milestone in range(1, max_tier + 1):
|
||||
for slot in range(1, number_of_slots_per_milestone_for_game + 1):
|
||||
if for_data_package:
|
||||
location_table.append(HubSlot(tier, milestone, slot, hub_location_id))
|
||||
else:
|
||||
if tier <= len(self.game_logic.hub_layout) \
|
||||
if tier <= max_tier \
|
||||
and milestone <= len(self.game_logic.hub_layout[tier - 1]) \
|
||||
and slot <= self.game_logic.slots_per_milestone:
|
||||
and slot <= number_of_slots_per_milestone_for_game:
|
||||
|
||||
location_table.append(HubSlot(tier, milestone, slot, hub_location_id))
|
||||
|
||||
hub_location_id += 1
|
||||
@@ -356,11 +366,13 @@ class Locations():
|
||||
|
||||
location_table.extend(
|
||||
ElevatorTier(index, self.state_logic, self.game_logic)
|
||||
for index, parts in enumerate(self.game_logic.space_elevator_tiers))
|
||||
for index, parts in enumerate(self.game_logic.space_elevator_tiers)
|
||||
if index < self.options.final_elevator_package)
|
||||
location_table.extend(
|
||||
part
|
||||
for part_name, recipes in self.game_logic.recipes.items()
|
||||
for part in Part.get_parts(self.state_logic, recipes, part_name, self.items))
|
||||
for part in Part.get_parts(self.state_logic, recipes, part_name, self.items)
|
||||
if part in self.critical_path.potential_required_parts)
|
||||
location_table.extend(
|
||||
EventBuilding(self.game_logic, self.state_logic, name, building)
|
||||
for name, building in self.game_logic.buildings.items())
|
||||
@@ -370,28 +382,28 @@ class Locations():
|
||||
|
||||
return location_table
|
||||
|
||||
def get_drop_pod_locations(self) -> List[LocationData]:
|
||||
def get_drop_pod_locations(self, for_data_package: bool, max_tier: int) -> List[LocationData]:
|
||||
drop_pod_locations: List[DropPod] = []
|
||||
|
||||
bucket_size: int = 0
|
||||
drop_pod_data: List[DropPodData] = []
|
||||
|
||||
if self.game_logic:
|
||||
bucket_size = floor(
|
||||
(self.drop_pod_location_id_end - self.drop_pod_location_id_start) / len(self.game_logic.hub_layout))
|
||||
|
||||
bucket_size: int
|
||||
drop_pod_data: List[DropPodData]
|
||||
if for_data_package:
|
||||
bucket_size = 0
|
||||
drop_pod_data = []
|
||||
else:
|
||||
bucket_size = floor((self.drop_pod_location_id_end - self.drop_pod_location_id_start) / max_tier)
|
||||
drop_pod_data = self.game_logic.drop_pods
|
||||
# sort, easily obtainable first, should be deterministic
|
||||
drop_pod_data.sort(key = lambda data: ("!" if data.item == None else data.item) + str(data.x - data.z))
|
||||
|
||||
for location_id in range(self.drop_pod_location_id_start, self.drop_pod_location_id_end + 1):
|
||||
if not self.game_logic or not self.state_logic or not self.options:
|
||||
if for_data_package:
|
||||
drop_pod_locations.append(DropPod(DropPodData(0, 0, 0, None, 0), None, location_id, 1, False))
|
||||
else:
|
||||
location_id_normalized: int = location_id - self.drop_pod_location_id_start
|
||||
data: DropPodData = drop_pod_data[location_id_normalized]
|
||||
can_hold_progression: bool = location_id_normalized < self.options.hard_drive_progression_limit.value
|
||||
tier = min(ceil((location_id_normalized + 1) / bucket_size), len(self.game_logic.hub_layout))
|
||||
tier = min(ceil((location_id_normalized + 1) / bucket_size), max_tier)
|
||||
|
||||
drop_pod_locations.append(DropPod(data, self.state_logic, location_id, tier, can_hold_progression))
|
||||
|
||||
|
||||
@@ -44,13 +44,13 @@ class ChoiceMap(Choice, metaclass=ChoiceMapMeta):
|
||||
|
||||
class ElevatorTier(NamedRange):
|
||||
"""
|
||||
Ship these Space Elevator packages to finish.
|
||||
Does nothing if *Space Elevator Tier* goal is not enabled.
|
||||
Put these Shipments to Space Elevator packages in logic.
|
||||
if your goal selection contains *Space Elevator Tier* then the goal will be to complete these shipments.
|
||||
"""
|
||||
display_name = "Goal: Space Elevator shipment"
|
||||
default = 2
|
||||
range_start = 1
|
||||
range_end = 4
|
||||
range_end = 5
|
||||
special_range_names = {
|
||||
"one package (tiers 1-2)": 1,
|
||||
"two packages (tiers 1-4)": 2,
|
||||
|
||||
@@ -42,6 +42,9 @@ def create_regions_and_return_locations(world: MultiWorld, options: Satisfactory
|
||||
]
|
||||
|
||||
for hub_tier, milestones_per_hub_tier in enumerate(game_logic.hub_layout, 1):
|
||||
if (hub_tier > (options.final_elevator_package * 2)):
|
||||
break
|
||||
|
||||
region_names.append(f"Hub Tier {hub_tier}")
|
||||
|
||||
for minestone, _ in enumerate(milestones_per_hub_tier, 1):
|
||||
@@ -85,18 +88,27 @@ def create_regions_and_return_locations(world: MultiWorld, options: Satisfactory
|
||||
super_early_game_buildings.append("Conveyor Splitter")
|
||||
super_early_game_buildings.append("Conveyor Merger")
|
||||
|
||||
if options.final_elevator_package == 1:
|
||||
super_early_game_buildings.append(early_game_buildings)
|
||||
|
||||
connect(regions, "Menu", "Overworld")
|
||||
connect(regions, "Overworld", "Hub Tier 1")
|
||||
connect(regions, "Hub Tier 1", "Hub Tier 2",
|
||||
lambda state: state_logic.can_build_all(state, super_early_game_buildings))
|
||||
connect(regions, "Hub Tier 2", "Hub Tier 3", lambda state: state.has("Elevator Tier 1", player)
|
||||
|
||||
if options.final_elevator_package >= 2:
|
||||
connect(regions, "Hub Tier 2", "Hub Tier 3", lambda state: state.has("Elevator Tier 1", player)
|
||||
and state_logic.can_build_all(state, early_game_buildings))
|
||||
connect(regions, "Hub Tier 3", "Hub Tier 4")
|
||||
connect(regions, "Hub Tier 4", "Hub Tier 5", lambda state: state.has("Elevator Tier 2", player))
|
||||
connect(regions, "Hub Tier 5", "Hub Tier 6")
|
||||
connect(regions, "Hub Tier 6", "Hub Tier 7", lambda state: state.has("Elevator Tier 3", player))
|
||||
connect(regions, "Hub Tier 7", "Hub Tier 8")
|
||||
connect(regions, "Hub Tier 8", "Hub Tier 9", lambda state: state.has("Elevator Tier 4", player))
|
||||
connect(regions, "Hub Tier 3", "Hub Tier 4")
|
||||
if options.final_elevator_package >= 3:
|
||||
connect(regions, "Hub Tier 4", "Hub Tier 5", lambda state: state.has("Elevator Tier 2", player))
|
||||
connect(regions, "Hub Tier 5", "Hub Tier 6")
|
||||
if options.final_elevator_package >= 4:
|
||||
connect(regions, "Hub Tier 6", "Hub Tier 7", lambda state: state.has("Elevator Tier 3", player))
|
||||
connect(regions, "Hub Tier 7", "Hub Tier 8")
|
||||
if options.final_elevator_package >= 5:
|
||||
connect(regions, "Hub Tier 8", "Hub Tier 9", lambda state: state.has("Elevator Tier 4", player))
|
||||
|
||||
connect(regions, "Overworld", "Gas Area", lambda state:
|
||||
state_logic.can_produce_all(state, ("Gas Mask", "Gas Filter")))
|
||||
connect(regions, "Overworld", "Radioactive Area", lambda state:
|
||||
@@ -112,6 +124,9 @@ def create_regions_and_return_locations(world: MultiWorld, options: Satisfactory
|
||||
return logic_rule
|
||||
|
||||
for hub_tier, milestones_per_hub_tier in enumerate(game_logic.hub_layout, 1):
|
||||
if (hub_tier > (options.final_elevator_package * 2)):
|
||||
break
|
||||
|
||||
for minestone, parts_per_milestone in enumerate(milestones_per_hub_tier, 1):
|
||||
connect(regions, f"Hub Tier {hub_tier}", f"Hub {hub_tier}-{minestone}",
|
||||
can_produce_all_allowing_handcrafting(parts_per_milestone.keys()))
|
||||
|
||||
@@ -38,10 +38,7 @@ class StateLogic:
|
||||
return power_level is None or state.has(building_event_prefix + power_level.to_name(), self.player)
|
||||
|
||||
def can_produce_all(self, state: CollectionState, parts: Optional[Iterable[str]]) -> bool:
|
||||
if parts and "SAM" in parts:
|
||||
debug = "Now"
|
||||
|
||||
return parts is None or \
|
||||
return parts is None or \
|
||||
state.has_all(map(self.to_part_event, parts), self.player)
|
||||
|
||||
def can_produce_all_allowing_handcrafting(self, state: CollectionState, logic: GameLogic,
|
||||
@@ -80,7 +77,9 @@ class StateLogic:
|
||||
and self.can_produce_all(state, recipe.inputs)
|
||||
|
||||
def is_game_phase(self, state: CollectionState, phase: int) -> bool:
|
||||
return state.has(f"Elevator Tier {phase}", self.player)
|
||||
limited_phase = min(self.options.final_elevator_package * 2, phase)
|
||||
|
||||
return state.has(f"Elevator Tier {limited_phase}", self.player)
|
||||
|
||||
@staticmethod
|
||||
def to_part_event(part: str) -> str:
|
||||
|
||||
@@ -6,6 +6,7 @@ from .Locations import Locations, LocationData
|
||||
from .StateLogic import EventId, StateLogic
|
||||
from .Options import SatisfactoryOptions, Placement
|
||||
from .Regions import SatisfactoryLocation, create_regions_and_return_locations
|
||||
from .CriticalPathCalculator import CriticalPathCalculator
|
||||
from .Web import SatisfactoryWebWorld
|
||||
from ..AutoWorld import World
|
||||
|
||||
@@ -30,6 +31,7 @@ class SatisfactoryWorld(World):
|
||||
game_logic: ClassVar[GameLogic] = GameLogic()
|
||||
state_logic: StateLogic
|
||||
items: Items
|
||||
critical_path: CriticalPathCalculator
|
||||
|
||||
def __init__(self, multiworld: "MultiWorld", player: int):
|
||||
super().__init__(multiworld, player)
|
||||
@@ -37,8 +39,11 @@ class SatisfactoryWorld(World):
|
||||
|
||||
|
||||
def generate_early(self) -> None:
|
||||
self.options.final_elevator_package.value = 1
|
||||
|
||||
self.state_logic = StateLogic(self.player, self.options)
|
||||
self.items = Items(self.player, self.game_logic, self.random, self.options)
|
||||
self.critical_path = CriticalPathCalculator(self.game_logic, self.random, self.options)
|
||||
self.items = Items(self.player, self.game_logic, self.random, self.options, self.critical_path)
|
||||
|
||||
if not self.options.goal_selection.value:
|
||||
raise Exception("""Satisfactory: player {} needs to choose a goal, the option goal_selection is empty"""
|
||||
@@ -65,7 +70,7 @@ class SatisfactoryWorld(World):
|
||||
|
||||
def create_regions(self) -> None:
|
||||
locations: List[LocationData] = \
|
||||
Locations(self.game_logic, self.options, self.state_logic, self.items).get_locations()
|
||||
Locations(self.game_logic, self.options, self.state_logic, self.items, self.critical_path).get_locations()
|
||||
create_regions_and_return_locations(
|
||||
self.multiworld, self.options, self.player, self.game_logic, self.state_logic, locations)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user