mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-22 07:35:37 -07:00
* Added Satisfactory to latest master * Fixed hard drive from containing the mam + incremented default value for harddrive progression * Apply cherry pick of 3076259 * Apply cherry pick of 6114a55 * Clarify Point goal behavior (https://github.com/Jarno458/SatisfactoryArchipelagoMod/issues/98) * Update Setup guide and info page * Add links to Gifting and Energy Link compatible games. Add info on Hard Drive behavior * Fix typos * Update hard drive behavior description * Hopefully fixed the mam from getting placed behind harddrives * Add 1 "Bundle: Solid Biofuel" to default starting items (for later chainsaw usage or early power gen) * Add info/warning about save setup failure bug * Add notes about dedicated server setup * Fixes: `TypeError: 'set' object is not subscriptable` random.choice does not work over set objects, cast to a list to allow 'trap_selection_override' * progrees i think * Fixed some bugs * Progress commmit incase my pc crashes * progress i think as test passed * I guess test pass, game still unbeatable tho * its generating * Some refactorings * Fixed generation with different elevator tiers * Remove debug statement * Fix this link. * Implemented abstract base classes + some fixes * Implemented many many new options * Yay more stuff * Fixed renaming of filters * Added 1.1 stuffs * Added options groups and presets * Fixes after variable renmame * Added recipy groups for easyer hinting * Implemented random Tier 0 * Updated slot_data * Latest update for 1.1 * Applied cheaper building costs of assembler and foundry * Implemented exploration cost in slot_data * Fixed exposing option type * Add goal time estimates * Trap info * Added support for Universal Tracker Put more things in the never exclude pool for a more familiar gameplay * Added iron ore to build hub * Added Dark Matter Crystals * Added Single Dark Matter Crystals * Fixed typo in options preset * Update setup directions and info * Options formatting fixes, lower minimum ExplorationCollectableCount, add new Explorer starting inventory items preset * Fixed incorrect description on the options * Reduce Portable Miner and Reinforced Iron Plate quantities in "Skip Tutorial Inspired" starting preset * Fixed options pickling error * Reworked logic to no longer include Single: items as filler Reworked logic for more performance Reworked logic to always put useful equipment in pool * Fixed Itemlinks Removed space elevator parts from fillers Removed more AWESOME shop purchaseables from minimal item pool Added all equipment to minimal item pool Removed non fissile and fertile uranium from minimal item pool Removed portal from minimal item pool Removed Ionized fuel from minimal item pool Removed recipes for Hoverpack and Turbo Rifle Ammo from minimal item pool Lowered the chance for rolling steel on randomized starter recipes * Fixed hub milestone item leaking to into wrong milestones * Fixed unlock cost of geothermal generator * Fixed itemlinks again * Add troubleshooting note about hoverpacks * Add starting inventory bundle delivery info * Added hint generation at generation time Harddrive locations now go from 1-100 rather then 0-99 * Update __init__.py Fixed mistake * Cleaned docs to be better suited to get verified * Update CODEOWNERS Added Satisfactory * Update README.md Added Satisfactory * Restructure and expand setup page to instruct both players and hosts * Add terms entry for Archipelago mod * Fixed generation of traps * Added Robb as code owner * Restore tests to original state * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix additional typos from code review * Implemented fix for itterating enum flags on python 3.10 * Update en_Satisfactory.md * Update setup_en.md * Apply suggestions from code review Co-authored-by: Scipio Wright <scipiowright@gmail.com> * more world > multiworld * Clarify universal tracker behavior * Fix typos * Info on smart hinting system * Move list of additional mods to a page on the mod GitHub * Restore revamped setup guide that other commits overwrote Originally frombe26511205,d8bd1aaf04* Removed bundle of ficsit coupons from the from the item pool added estimated completion times to space elevator option description * Apply suggestions from code review Co-authored-by: Scipio Wright <scipiowright@gmail.com> * Wording * Fix typo * Update with changes from ToBeVerified branch * Update note about gameplay options * Update note about gameplay options * Improved universal tracker handling * Improved universal tracker + modernized code a bit * Fixed bugs that where re-introduced * Added Recipe: Excited Photonic Matter * Removed python 3.9 workaround * Fixed * Apply suggestions from code review Co-authored-by: Scipio Wright <scipiowright@gmail.com> * Streamlined handle craftable logic by using itterable rather then tuple Removed dict.keys as the dict itzelf already enumerates over keys * Updated option description * Fixed typing * More info on goal completion conditions * More info on goal completion conditions (093fe38b6e) * Apply suggestions from code review Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com> * Implemented review results * PEP8 stuff * More PEP8 * Rename ElevatorTier->ElevatorPhase and related for clarity and consistency. Untested * speedups part1 * speedsups on part rules * Fix formatting * fix `Elevator Tier #` string literals missed in rename * Remove unused/duplicate imports + organize imports, `== None` to `is None` * Fixed after merge * Updated values + removed TODO * PEPed up the code * Small refactorings * Updated name slot data to phase * Fix hint creation * Clarify wording of elevator goal * Review result * Fixed minor typo in option * Update option time estimates --------- Co-authored-by: Rob B <computerguy440+gh@gmail.com> Co-authored-by: ProverbialPennance <36955346+ProverbialPennance@users.noreply.github.com> Co-authored-by: Joe Amenta <airbreather@linux.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Scipio Wright <scipiowright@gmail.com> Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com> Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
172 lines
7.4 KiB
Python
172 lines
7.4 KiB
Python
from typing import Optional, Callable, ClassVar, Tuple
|
|
from collections.abc import Iterable
|
|
from BaseClasses import CollectionState
|
|
from .GameLogic import Recipe, PowerInfrastructureLevel
|
|
from .Options import SatisfactoryOptions
|
|
from .CriticalPathCalculator import CriticalPathCalculator
|
|
|
|
EventId: Optional[int] = None
|
|
|
|
part_event_prefix = "Can Produce: "
|
|
building_event_prefix = "Can Build: "
|
|
|
|
|
|
def true_rule(_: CollectionState) -> bool:
|
|
return True
|
|
|
|
|
|
def to_part_event(part: str) -> str:
|
|
return part_event_prefix + part
|
|
|
|
|
|
def to_building_event(part: str) -> str:
|
|
return building_event_prefix + part
|
|
|
|
|
|
def to_belt_name(power_level: int) -> str:
|
|
return "Conveyor Mk." + str(power_level)
|
|
|
|
|
|
class StateLogic:
|
|
player: int
|
|
options: SatisfactoryOptions
|
|
critical_path: CriticalPathCalculator
|
|
initial_unlocked_items: set[str]
|
|
|
|
pipe_events: ClassVar[tuple[str, str]] = \
|
|
tuple(to_building_event(building) for building in ("Pipes Mk.1", "Pipes Mk.2"))
|
|
pump_events: ClassVar[tuple[str, str]] = \
|
|
tuple(to_building_event(building) for building in ("Pipeline Pump Mk.1", "Pipeline Pump Mk.2"))
|
|
hazmat_events: ClassVar[tuple[str, str]] = \
|
|
tuple(to_part_event(part) for part in ("Hazmat Suit", "Iodine-Infused Filter"))
|
|
belt_events: ClassVar[tuple[tuple[str, ...], ...]] = tuple(
|
|
tuple(map(to_building_event, map(to_belt_name, range(speed, 6))))
|
|
for speed in range(1, 6)
|
|
)
|
|
|
|
pipes_rule: Callable[[CollectionState], bool]
|
|
radio_active_rule: Callable[[CollectionState], bool]
|
|
belt_rules: Tuple[Callable[[CollectionState], bool], ...]
|
|
|
|
def __init__(self, player: int, options: SatisfactoryOptions, critical_path: CriticalPathCalculator):
|
|
self.player = player
|
|
self.options = options
|
|
self.critical_path = critical_path
|
|
|
|
self.pipes_rule = self.get_requires_pipes_rule()
|
|
self.radio_active_rule = self.get_requires_hazmat_rule()
|
|
self.belt_rule = tuple(self.get_belt_speed_rule(speed) for speed in range(1, 6))
|
|
|
|
def has_recipe(self, state: CollectionState, recipe: Recipe) -> bool:
|
|
return state.has(recipe.name, self.player) or recipe.name in self.critical_path.implicitly_unlocked
|
|
|
|
def can_build(self, state: CollectionState, building_name: Optional[str]) -> bool:
|
|
return building_name is None or state.has(building_event_prefix + building_name, self.player)
|
|
|
|
def can_build_any(self, state: CollectionState, building_names: Optional[Iterable[str]]) -> bool:
|
|
return building_names is None or \
|
|
state.has_any(map(to_building_event, building_names), self.player)
|
|
|
|
def can_build_all(self, state: CollectionState, building_names: Optional[Iterable[str]]) -> bool:
|
|
return building_names is None or \
|
|
state.has_all(map(to_building_event, building_names), self.player)
|
|
|
|
def can_produce(self, state: CollectionState, part_name: Optional[str]) -> bool:
|
|
return part_name is None or state.has(part_event_prefix + part_name, self.player)
|
|
|
|
def can_power(self, state: CollectionState, power_level: Optional[PowerInfrastructureLevel]) -> bool:
|
|
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:
|
|
return parts is None or \
|
|
state.has_all(map(to_part_event, parts), self.player)
|
|
|
|
def can_handcraft_single_part(self, state: CollectionState, part: str) -> bool:
|
|
if self.can_produce(state, part):
|
|
return True
|
|
|
|
if part not in self.critical_path.handcraftable_parts:
|
|
return False
|
|
|
|
recipes: list[Recipe] = self.critical_path.handcraftable_parts[part]
|
|
return any(
|
|
self.has_recipe(state, recipe)
|
|
and (not recipe.inputs or all(
|
|
self.can_handcraft_single_part(state, recipe_part)
|
|
for recipe_part in recipe.inputs))
|
|
for recipe in recipes)
|
|
|
|
def get_can_produce_all_allowing_handcrafting_rule(self, parts: Optional[Iterable[str]]) \
|
|
-> Callable[[CollectionState], bool]:
|
|
if not parts:
|
|
return true_rule
|
|
|
|
return lambda state: all(self.can_handcraft_single_part(state, part) for part in parts)
|
|
|
|
def get_requires_pipes_rule(self) -> Callable[[CollectionState], bool]:
|
|
return lambda state: \
|
|
state.has_any(self.pipe_events, self.player) and state.has_any(self.pump_events, self.player)
|
|
|
|
def get_requires_hazmat_rule(self) -> Callable[[CollectionState], bool]:
|
|
return lambda state: state.has_all(self.hazmat_events, self.player)
|
|
|
|
def get_belt_speed_rule(self, belt_speed: int) -> Callable[[CollectionState], bool]:
|
|
return lambda state: state.has_any(self.belt_events[belt_speed], self.player)
|
|
|
|
def is_recipe_producible(self, state: CollectionState, recipe: Recipe) -> bool:
|
|
return self.has_recipe(state, recipe) \
|
|
and self.can_build(state, recipe.building) \
|
|
and self.can_produce_all(state, recipe.inputs)
|
|
|
|
def get_can_produce_specific_recipe_for_part_rule(self, recipe: Recipe) -> Callable[[CollectionState], bool]:
|
|
if recipe.needs_pipes:
|
|
if recipe.is_radio_active:
|
|
if recipe.minimal_belt_speed:
|
|
return lambda state: \
|
|
self.is_recipe_producible(state, recipe) \
|
|
and self.pipes_rule(state) \
|
|
and self.radio_active_rule(state) \
|
|
and self.belt_rule[recipe.minimal_belt_speed - 1]
|
|
else:
|
|
return lambda state: \
|
|
self.is_recipe_producible(state, recipe) \
|
|
and self.pipes_rule(state) \
|
|
and self.radio_active_rule(state)
|
|
else:
|
|
if recipe.minimal_belt_speed:
|
|
return lambda state: \
|
|
self.is_recipe_producible(state, recipe) \
|
|
and self.pipes_rule(state) \
|
|
and self.belt_rule[recipe.minimal_belt_speed - 1]
|
|
else:
|
|
return lambda state: \
|
|
self.is_recipe_producible(state, recipe) \
|
|
and self.pipes_rule(state)
|
|
else:
|
|
if recipe.is_radio_active:
|
|
if recipe.minimal_belt_speed:
|
|
return lambda state: \
|
|
self.is_recipe_producible(state, recipe) \
|
|
and self.radio_active_rule(state) \
|
|
and self.belt_rule[recipe.minimal_belt_speed - 1]
|
|
else:
|
|
return lambda state: \
|
|
self.is_recipe_producible(state, recipe) \
|
|
and self.radio_active_rule(state)
|
|
else:
|
|
if recipe.minimal_belt_speed:
|
|
return lambda state: \
|
|
self.is_recipe_producible(state, recipe) \
|
|
and self.belt_rule[recipe.minimal_belt_speed - 1]
|
|
else:
|
|
return lambda state: \
|
|
self.is_recipe_producible(state, recipe)
|
|
|
|
def is_elevator_phase(self, state: CollectionState, phase: int) -> bool:
|
|
limited_phase = min(self.options.final_elevator_phase - 1, phase)
|
|
|
|
if limited_phase != 0:
|
|
return state.has(f"Elevator Phase {limited_phase}", self.player)
|
|
else:
|
|
return True
|