mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-07-18 14:00:41 -07:00
Merge branch 'main' into add_dark_souls_III
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import typing
|
||||
|
||||
from BaseClasses import MultiWorld
|
||||
from Options import Choice, Range, Option, Toggle, DefaultOnToggle, DeathLink
|
||||
|
||||
|
||||
@@ -27,6 +28,35 @@ class Goal(Choice):
|
||||
option_hand_in = 2
|
||||
|
||||
|
||||
class OpenPyramid(Choice):
|
||||
"""Determines whether the hole at the top of pyramid is open.
|
||||
Goal will open the pyramid if the goal requires you to kill Ganon, without needing to kill Agahnim 2.
|
||||
Auto is the same as goal except if Ganon's dropdown is in another location, the hole will be closed."""
|
||||
display_name = "Open Pyramid Hole"
|
||||
option_closed = 0
|
||||
option_open = 1
|
||||
option_goal = 2
|
||||
option_auto = 3
|
||||
default = option_goal
|
||||
|
||||
alias_true = option_open
|
||||
alias_false = option_closed
|
||||
alias_yes = option_open
|
||||
alias_no = option_closed
|
||||
|
||||
def to_bool(self, world: MultiWorld, player: int) -> bool:
|
||||
if self.value == self.option_goal:
|
||||
return world.goal[player] in {'crystals', 'ganontriforcehunt', 'localganontriforcehunt', 'ganonpedestal'}
|
||||
elif self.value == self.option_auto:
|
||||
return world.goal[player] in {'crystals', 'ganontriforcehunt', 'localganontriforcehunt', 'ganonpedestal'} \
|
||||
and (world.shuffle[player] in {'vanilla', 'dungeonssimple', 'dungeonsfull', 'dungeonscrossed'} or not
|
||||
world.shuffle_ganon)
|
||||
elif self.value == self.option_open:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class DungeonItem(Choice):
|
||||
value: int
|
||||
option_original_dungeon = 0
|
||||
@@ -331,6 +361,7 @@ class AllowCollect(Toggle):
|
||||
alttp_options: typing.Dict[str, type(Option)] = {
|
||||
"crystals_needed_for_gt": CrystalsTower,
|
||||
"crystals_needed_for_ganon": CrystalsGanon,
|
||||
"open_pyramid": OpenPyramid,
|
||||
"bigkey_shuffle": bigkey_shuffle,
|
||||
"smallkey_shuffle": smallkey_shuffle,
|
||||
"compass_shuffle": compass_shuffle,
|
||||
|
||||
+1
-1
@@ -1247,7 +1247,7 @@ def patch_rom(world, rom, player, enemized):
|
||||
rom.write_bytes(0x50563, [0x3F, 0x14]) # disable below ganon chest
|
||||
rom.write_byte(0x50599, 0x00) # disable below ganon chest
|
||||
rom.write_bytes(0xE9A5, [0x7E, 0x00, 0x24]) # disable below ganon chest
|
||||
rom.write_byte(0x18008B, 0x01 if world.open_pyramid[player] else 0x00) # pre-open Pyramid Hole
|
||||
rom.write_byte(0x18008B, 0x01 if world.open_pyramid[player].to_bool(world, player) else 0x00) # pre-open Pyramid Hole
|
||||
rom.write_byte(0x18008C, 0x01 if world.crystals_needed_for_gt[
|
||||
player] == 0 else 0x00) # GT pre-opened if crystal requirement is 0
|
||||
rom.write_byte(0xF5D73, 0xF0) # bees are catchable
|
||||
|
||||
@@ -176,17 +176,6 @@ class ALTTPWorld(World):
|
||||
def create_regions(self):
|
||||
player = self.player
|
||||
world = self.world
|
||||
if world.open_pyramid[player] == 'goal':
|
||||
world.open_pyramid[player] = world.goal[player] in {'crystals', 'ganontriforcehunt',
|
||||
'localganontriforcehunt', 'ganonpedestal'}
|
||||
elif world.open_pyramid[player] == 'auto':
|
||||
world.open_pyramid[player] = world.goal[player] in {'crystals', 'ganontriforcehunt',
|
||||
'localganontriforcehunt', 'ganonpedestal'} and \
|
||||
(world.shuffle[player] in {'vanilla', 'dungeonssimple', 'dungeonsfull',
|
||||
'dungeonscrossed'} or not world.shuffle_ganon)
|
||||
else:
|
||||
world.open_pyramid[player] = {'on': True, 'off': False, 'yes': True, 'no': False}.get(
|
||||
world.open_pyramid[player], 'auto')
|
||||
|
||||
world.triforce_pieces_available[player] = max(world.triforce_pieces_available[player],
|
||||
world.triforce_pieces_required[player])
|
||||
|
||||
@@ -7,6 +7,8 @@ import threading
|
||||
import base64
|
||||
from typing import Set, List, TextIO
|
||||
|
||||
from worlds.sm.variaRandomizer.graph.graph_utils import GraphUtils
|
||||
|
||||
logger = logging.getLogger("Super Metroid")
|
||||
|
||||
from .Locations import lookup_name_to_id as locations_lookup_name_to_id
|
||||
@@ -654,11 +656,10 @@ class SMLocation(Location):
|
||||
def can_comeback(self, state: CollectionState, item: Item):
|
||||
randoExec = state.world.worlds[self.player].variaRando.randoExec
|
||||
for key in locationsDict[self.name].AccessFrom.keys():
|
||||
if (randoExec.areaGraph.canAccess( state.smbm[self.player],
|
||||
key,
|
||||
randoExec.graphSettings.startAP,
|
||||
state.smbm[self.player].maxDiff,
|
||||
None)):
|
||||
if (randoExec.areaGraph.canAccessList( state.smbm[self.player],
|
||||
key,
|
||||
[randoExec.graphSettings.startAP, 'Landing Site'] if not GraphUtils.isStandardStart(randoExec.graphSettings.startAP) else ['Landing Site'],
|
||||
state.smbm[self.player].maxDiff)):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@@ -367,6 +367,22 @@ class AccessGraph(object):
|
||||
#print("canAccess: {}".format(can))
|
||||
return can
|
||||
|
||||
# test access from an access point to a list of others, given an optional item
|
||||
def canAccessList(self, smbm, srcAccessPointName, destAccessPointNameList, maxDiff, item=None):
|
||||
if item is not None:
|
||||
smbm.addItem(item)
|
||||
#print("canAccess: item: {}, src: {}, dest: {}".format(item, srcAccessPointName, destAccessPointName))
|
||||
destAccessPointList = [self.accessPoints[destAccessPointName] for destAccessPointName in destAccessPointNameList]
|
||||
srcAccessPoint = self.accessPoints[srcAccessPointName]
|
||||
availAccessPoints = self.getAvailableAccessPoints(srcAccessPoint, smbm, maxDiff, item)
|
||||
can = any(ap in availAccessPoints for ap in destAccessPointList)
|
||||
# if not can:
|
||||
# self.log.debug("canAccess KO: avail = {}".format([ap.Name for ap in availAccessPoints.keys()]))
|
||||
if item is not None:
|
||||
smbm.removeItem(item)
|
||||
#print("canAccess: {}".format(can))
|
||||
return can
|
||||
|
||||
# returns a list of AccessPoint instances from srcAccessPointName to destAccessPointName
|
||||
# (not including source ap)
|
||||
# or None if no possible path
|
||||
|
||||
@@ -341,6 +341,8 @@ class VariaRandomizer:
|
||||
if preset == 'custom':
|
||||
PresetLoader.factory(world.custom_preset[player].value).load(self.player)
|
||||
elif preset == 'varia_custom':
|
||||
if len(world.varia_custom_preset[player].value) == 0:
|
||||
raise Exception("varia_custom was chosen but varia_custom_preset is missing.")
|
||||
url = 'https://randommetroidsolver.pythonanywhere.com/presetWebService'
|
||||
preset_name = next(iter(world.varia_custom_preset[player].value))
|
||||
payload = '{{"preset": "{}"}}'.format(preset_name)
|
||||
|
||||
Reference in New Issue
Block a user