Merge branch 'main' into add_dark_souls_III

This commit is contained in:
Marechal-l
2022-07-14 11:16:21 +02:00
10 changed files with 184 additions and 40 deletions
+31
View File
@@ -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
View File
@@ -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
-11
View File
@@ -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])
+6 -5
View File
@@ -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
+16
View File
@@ -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
+2
View File
@@ -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)