Stonewall generation changed to pre-open wall if necessary.
GT Mini bosses no longer drop heart containers. Crystal switch logic during generation updated.
This commit is contained in:
@@ -870,6 +870,7 @@ class Region(object):
|
|||||||
self.hint_text = hint
|
self.hint_text = hint
|
||||||
self.recursion_count = 0
|
self.recursion_count = 0
|
||||||
self.player = player
|
self.player = player
|
||||||
|
self.crystal_switch = False
|
||||||
|
|
||||||
def can_reach(self, state):
|
def can_reach(self, state):
|
||||||
if state.stale[self.player]:
|
if state.stale[self.player]:
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from collections import defaultdict
|
|||||||
import logging
|
import logging
|
||||||
import operator as op
|
import operator as op
|
||||||
import time
|
import time
|
||||||
|
from enum import unique, Flag
|
||||||
|
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from BaseClasses import RegionType, Door, DoorType, Direction, Sector, CrystalBarrier
|
from BaseClasses import RegionType, Door, DoorType, Direction, Sector, CrystalBarrier
|
||||||
@@ -1298,6 +1299,11 @@ def check_for_pinball_fix(state, bad_region, world, player):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@unique
|
||||||
|
class DROptions(Flag):
|
||||||
|
Eternal_Mini_Bosses = 0x01 # If on, GT minibosses marked as defeated when they try to spawn a heart
|
||||||
|
Open_Desert_Wall = 0x80 # If on, pre opens the desert wall, no fire required
|
||||||
|
|
||||||
# DATA GOES DOWN HERE
|
# DATA GOES DOWN HERE
|
||||||
|
|
||||||
logical_connections = [
|
logical_connections = [
|
||||||
|
|||||||
+10
-222
@@ -51,43 +51,17 @@ def validate_tr(builder, entrance_region_names, world, player):
|
|||||||
|
|
||||||
|
|
||||||
def generate_dungeon(builder, entrance_region_names, split_dungeon, world, player):
|
def generate_dungeon(builder, entrance_region_names, split_dungeon, world, player):
|
||||||
builder_list = [builder]
|
stonewall = check_for_stonewall(builder)
|
||||||
queue = deque(builder_list)
|
sector = generate_dungeon_main(builder, entrance_region_names, split_dungeon, world, player)
|
||||||
finished_stonewalls = []
|
if stonewall and not stonewall_valid(stonewall):
|
||||||
while len(queue) > 0:
|
builder.pre_open_stonewall = stonewall
|
||||||
builder = queue.popleft()
|
return sector
|
||||||
stonewall = check_for_stonewall(builder, finished_stonewalls)
|
|
||||||
if stonewall is not None:
|
|
||||||
# todo: kill drop exceptions
|
|
||||||
entrances = [x for x in entrance_region_names if x not in ['Skull Back Drop']]
|
|
||||||
dungeon_map = stonewall_dungeon_builder(builder, stonewall, entrances, world, player)
|
|
||||||
builder_list.remove(builder)
|
|
||||||
for sub_builder in dungeon_map.values():
|
|
||||||
builder_list.append(sub_builder)
|
|
||||||
queue.append(sub_builder)
|
|
||||||
finished_stonewalls.append(stonewall)
|
|
||||||
if len(builder_list) == 1:
|
|
||||||
return generate_dungeon_main(builder, entrance_region_names, split_dungeon, world, player)
|
|
||||||
else:
|
|
||||||
sector_list = []
|
|
||||||
for split_builder in builder_list:
|
|
||||||
sector = generate_dungeon_main(split_builder, split_builder.stonewall_entrances, True, world, player)
|
|
||||||
sector_list.append(sector)
|
|
||||||
master_sector = sector_list.pop()
|
|
||||||
for sub_sector in sector_list:
|
|
||||||
master_sector.regions.extend(sub_sector.regions)
|
|
||||||
master_sector.outstanding_doors.clear()
|
|
||||||
master_sector.r_name_set = None
|
|
||||||
for stonewall in finished_stonewalls:
|
|
||||||
if not stonewall_valid(stonewall):
|
|
||||||
raise Exception('Stonewall still reachable from wrong side')
|
|
||||||
return master_sector
|
|
||||||
|
|
||||||
|
|
||||||
def check_for_stonewall(builder, finished_stonewalls):
|
def check_for_stonewall(builder):
|
||||||
for sector in builder.sectors:
|
for sector in builder.sectors:
|
||||||
for door in sector.outstanding_doors:
|
for door in sector.outstanding_doors:
|
||||||
if door.stonewall and door not in finished_stonewalls:
|
if door.stonewall:
|
||||||
return door
|
return door
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -207,7 +181,8 @@ def gen_dungeon_info(name, available_sectors, entrance_regions, proposed_map, va
|
|||||||
if not door.stonewall and door not in proposed_map.keys():
|
if not door.stonewall and door not in proposed_map.keys():
|
||||||
hanger_set.add(door)
|
hanger_set.add(door)
|
||||||
parent = door.entrance.parent_region
|
parent = door.entrance.parent_region
|
||||||
init_state = ExplorationState(init_crystal, dungeon=name)
|
crystal_start = CrystalBarrier.Either if parent.crystal_switch else init_crystal
|
||||||
|
init_state = ExplorationState(crystal_start, dungeon=name)
|
||||||
init_state.big_key_special = start.big_key_special
|
init_state.big_key_special = start.big_key_special
|
||||||
o_state = extend_reachable_state_improved([parent], init_state, proposed_map,
|
o_state = extend_reachable_state_improved([parent], init_state, proposed_map,
|
||||||
valid_doors, False, world, player)
|
valid_doors, False, world, player)
|
||||||
@@ -1046,7 +1021,7 @@ class DungeonBuilder(object):
|
|||||||
self.path_entrances = None # used for pathing/key doors, I think
|
self.path_entrances = None # used for pathing/key doors, I think
|
||||||
self.split_flag = False
|
self.split_flag = False
|
||||||
|
|
||||||
self.stonewall_entrances = [] # used by stonewall system
|
self.pre_open_stonewall = None # used by stonewall system
|
||||||
|
|
||||||
self.candidates = None
|
self.candidates = None
|
||||||
self.key_doors_num = None
|
self.key_doors_num = None
|
||||||
@@ -1866,193 +1841,6 @@ def categorize_sectors(candidate_sectors):
|
|||||||
return crystal_switches, crystal_barriers, neutral_sectors, polarized_sectors
|
return crystal_switches, crystal_barriers, neutral_sectors, polarized_sectors
|
||||||
|
|
||||||
|
|
||||||
def stonewall_dungeon_builder(builder, stonewall, entrance_region_names, world, player):
|
|
||||||
logger = logging.getLogger('')
|
|
||||||
logger.info('Stonewall treatment')
|
|
||||||
candidate_sectors = dict.fromkeys(builder.sectors)
|
|
||||||
dungeon_map = {}
|
|
||||||
|
|
||||||
# split stonewall sector
|
|
||||||
region = stonewall.entrance.parent_region
|
|
||||||
sector = find_sector(region.name, candidate_sectors)
|
|
||||||
del candidate_sectors[sector]
|
|
||||||
stonewall_start = Sector()
|
|
||||||
stonewall_connector = Sector()
|
|
||||||
stonewall_start.outstanding_doors.append(stonewall)
|
|
||||||
stonewall_start.regions.append(region)
|
|
||||||
stonewall_start.entrance_sector = True
|
|
||||||
stonewall_start.branch_factor = 2
|
|
||||||
stonewall_connector.outstanding_doors += [x for x in sector.outstanding_doors if x != stonewall]
|
|
||||||
stonewall_connector.regions += [x for x in sector.regions if x != region]
|
|
||||||
define_sector_features([stonewall_connector, stonewall_start])
|
|
||||||
candidate_sectors[stonewall_start] = None
|
|
||||||
candidate_sectors[stonewall_connector] = None
|
|
||||||
global_pole = GlobalPolarity(candidate_sectors)
|
|
||||||
create_stone_builder(builder, dungeon_map, region, stonewall_start, candidate_sectors, global_pole)
|
|
||||||
origin_builder = create_origin_builder(builder, dungeon_map, entrance_region_names, stonewall_connector, candidate_sectors, global_pole)
|
|
||||||
|
|
||||||
if stonewall.name == 'Desert Wall Slide NW':
|
|
||||||
# not true if big shuffled or split
|
|
||||||
location_needed = not builder.split_flag and not world.bigkeyshuffle[player]
|
|
||||||
for sector in origin_builder.sectors:
|
|
||||||
location_needed &= sector.chest_locations == 0 or (sector.chest_locations == 1 and sector.big_chest_present)
|
|
||||||
if location_needed:
|
|
||||||
free_location_sectors = []
|
|
||||||
for sector in candidate_sectors:
|
|
||||||
if sector.chest_locations > 1 or (sector.chest_locations == 1 and not sector.big_chest_present):
|
|
||||||
free_location_sectors.append(sector)
|
|
||||||
valid = False
|
|
||||||
while not valid:
|
|
||||||
if len(free_location_sectors) == 0:
|
|
||||||
raise Exception('Cannot place a big key sector before the wall slide, ouch')
|
|
||||||
sector = random.choice(free_location_sectors)
|
|
||||||
free_location_sectors.remove(sector)
|
|
||||||
valid = global_pole.is_valid_choice(dungeon_map, origin_builder, [sector])
|
|
||||||
assign_sector(sector, origin_builder, candidate_sectors, global_pole)
|
|
||||||
return balance_split(candidate_sectors, dungeon_map, global_pole)
|
|
||||||
|
|
||||||
# dependent sector splits
|
|
||||||
# dependency_list = []
|
|
||||||
# removal = []
|
|
||||||
# for sector in candidate_sectors.keys():
|
|
||||||
# dependency = split_sector(sector)
|
|
||||||
# if dependency is not None:
|
|
||||||
# removal.append(sector)
|
|
||||||
# parent, child = dependency
|
|
||||||
# dependency_list.append((parent, child, sector))
|
|
||||||
# for sector in removal:
|
|
||||||
# del candidate_sectors[sector]
|
|
||||||
# retry_candidates = candidate_sectors.copy()
|
|
||||||
# tries = 0
|
|
||||||
# while tries < 10:
|
|
||||||
# try:
|
|
||||||
# # re-assign dependent regions
|
|
||||||
# for parent, child, original in dependency_list:
|
|
||||||
# chosen_builder = random.choice([stone_builder, origin_builder, None])
|
|
||||||
# if chosen_builder is None:
|
|
||||||
# candidate_sectors[original] = None
|
|
||||||
# elif chosen_builder == stone_builder:
|
|
||||||
# candidate_sectors[original] = None
|
|
||||||
# assign_sector(original, chosen_builder, candidate_sectors)
|
|
||||||
# else:
|
|
||||||
# candidate_sectors[parent] = None
|
|
||||||
# candidate_sectors[child] = None
|
|
||||||
# assign_sector(child, chosen_builder, candidate_sectors)
|
|
||||||
# return stonewall_split(candidate_sectors, dungeon_map)
|
|
||||||
# except NeutralizingException:
|
|
||||||
# tries += 1
|
|
||||||
# candidate_sectors = retry_candidates.copy()
|
|
||||||
# candidate_sectors[stonewall_start] = None
|
|
||||||
# candidate_sectors[stonewall_connector] = None
|
|
||||||
# stone_builder = create_stone_builder(builder, dungeon_map, region, stonewall_start, candidate_sectors)
|
|
||||||
# origin_builder = create_origin_builder(builder, dungeon_map, entrance_region_names, stonewall_connector, candidate_sectors)
|
|
||||||
#
|
|
||||||
# raise NeutralizingException('Unable to find a valid combination')
|
|
||||||
|
|
||||||
|
|
||||||
def stonewall_split(candidate_sectors, dungeon_map, global_pole):
|
|
||||||
logger = logging.getLogger('')
|
|
||||||
# categorize sectors
|
|
||||||
crystal_switches, crystal_barriers, neutral_sectors, polarized_sectors = categorize_sectors(candidate_sectors)
|
|
||||||
leftover = assign_crystal_switch_sectors(dungeon_map, crystal_switches, global_pole, len(crystal_barriers) > 0)
|
|
||||||
for sector in leftover:
|
|
||||||
if sector.polarity().is_neutral():
|
|
||||||
neutral_sectors[sector] = None
|
|
||||||
else:
|
|
||||||
polarized_sectors[sector] = None
|
|
||||||
# blue barriers
|
|
||||||
assign_crystal_barrier_sectors(dungeon_map, crystal_barriers, global_pole)
|
|
||||||
# polarity:
|
|
||||||
logger.info('-Re-balancing ' + next(iter(dungeon_map.keys())) + ' et al')
|
|
||||||
polarity_step_3(dungeon_map, polarized_sectors, global_pole, logger)
|
|
||||||
assign_polarized_sectors(dungeon_map, polarized_sectors, global_pole, logger)
|
|
||||||
# the rest
|
|
||||||
assign_the_rest(dungeon_map, neutral_sectors, global_pole)
|
|
||||||
return dungeon_map
|
|
||||||
|
|
||||||
|
|
||||||
def create_origin_builder(builder, dungeon_map, entrance_region_names, stonewall_connector, candidate_sectors, global_pole):
|
|
||||||
key = builder.name + ' Prewall'
|
|
||||||
dungeon_map[key] = origin_builder = DungeonBuilder(key)
|
|
||||||
origin_builder.stonewall_entrances += entrance_region_names
|
|
||||||
origin_builder.all_entrances = []
|
|
||||||
for ent in entrance_region_names:
|
|
||||||
sector = find_sector(ent, candidate_sectors)
|
|
||||||
if sector is not None:
|
|
||||||
for door in sector.outstanding_doors:
|
|
||||||
if not door.blocked:
|
|
||||||
origin_builder.all_entrances.append(ent)
|
|
||||||
assign_sector(sector, origin_builder, candidate_sectors, global_pole)
|
|
||||||
break
|
|
||||||
else: # already got assigned
|
|
||||||
origin_builder.all_entrances.append(ent)
|
|
||||||
assign_sector(stonewall_connector, origin_builder, candidate_sectors, global_pole)
|
|
||||||
return origin_builder
|
|
||||||
|
|
||||||
|
|
||||||
def create_stone_builder(builder, dungeon_map, region, stonewall_start, candidate_sectors, global_pole):
|
|
||||||
key = builder.name + ' Stonewall'
|
|
||||||
dungeon_map[key] = stone_builder = DungeonBuilder(key)
|
|
||||||
stone_builder.stonewall_entrances += [region.name]
|
|
||||||
stone_builder.all_entrances = [region.name]
|
|
||||||
stone_builder.branch_factor = 2
|
|
||||||
assign_sector(stonewall_start, stone_builder, candidate_sectors, global_pole)
|
|
||||||
return stone_builder
|
|
||||||
|
|
||||||
|
|
||||||
# def split_sector(sector):
|
|
||||||
# entrance_set = set()
|
|
||||||
# exit_map = {}
|
|
||||||
# visited_regions = {}
|
|
||||||
# min_cardinality = None
|
|
||||||
# for door in sector.outstanding_doors:
|
|
||||||
# reachable_doors = {door}
|
|
||||||
# start_region = door.entrance.parent_region
|
|
||||||
# visited = {start_region}
|
|
||||||
# queue = deque([start_region])
|
|
||||||
# while len(queue) > 0:
|
|
||||||
# region = queue.popleft()
|
|
||||||
# for ext in region.exits:
|
|
||||||
# connect = ext.connected_region
|
|
||||||
# if connect is not None and connect.type == RegionType.Dungeon and connect not in visited:
|
|
||||||
# visited.add(connect)
|
|
||||||
# queue.append(connect)
|
|
||||||
# elif ext.door in sector.outstanding_doors:
|
|
||||||
# reachable_doors.add(ext.door)
|
|
||||||
# visited_regions[door] = visited
|
|
||||||
# if len(reachable_doors) >= len(sector.outstanding_doors):
|
|
||||||
# entrance_set.add(door)
|
|
||||||
# else:
|
|
||||||
# door_cardinality = len(reachable_doors)
|
|
||||||
# if door_cardinality not in exit_map.keys():
|
|
||||||
# exit_map[door_cardinality] = set()
|
|
||||||
# exit_map[door_cardinality].add(door)
|
|
||||||
# if min_cardinality is None or door_cardinality < min_cardinality:
|
|
||||||
# min_cardinality = door_cardinality
|
|
||||||
# exit_set = set()
|
|
||||||
# if min_cardinality is not None:
|
|
||||||
# for cardinality, door_set in exit_map.items():
|
|
||||||
# if cardinality > min_cardinality:
|
|
||||||
# entrance_set.update(door_set)
|
|
||||||
# exit_set = exit_map[min_cardinality]
|
|
||||||
# if len(entrance_set) > 0 and len(exit_set) > 0:
|
|
||||||
# entrance_sector = Sector()
|
|
||||||
# exit_sector = Sector()
|
|
||||||
# entrance_sector.outstanding_doors.extend(entrance_set)
|
|
||||||
# region_set = set()
|
|
||||||
# for ent_door in entrance_set:
|
|
||||||
# region_set.update(visited_regions[ent_door])
|
|
||||||
# entrance_sector.regions.extend(region_set)
|
|
||||||
# exit_sector.outstanding_doors.extend(exit_set)
|
|
||||||
# region_set = set()
|
|
||||||
# for ext_door in exit_set:
|
|
||||||
# region_set.update(visited_regions[ext_door])
|
|
||||||
# exit_sector.regions.extend(region_set)
|
|
||||||
# define_sector_features([entrance_sector, exit_sector])
|
|
||||||
# return entrance_sector, exit_sector
|
|
||||||
# return None
|
|
||||||
|
|
||||||
|
|
||||||
class NeutralizingException(Exception):
|
class NeutralizingException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ from Fill import distribute_items_cutoff, distribute_items_staleness, distribute
|
|||||||
from ItemList import generate_itempool, difficulties, fill_prizes
|
from ItemList import generate_itempool, difficulties, fill_prizes
|
||||||
from Utils import output_path, parse_player_names
|
from Utils import output_path, parse_player_names
|
||||||
|
|
||||||
__version__ = '0.0.c-pre'
|
__version__ = '0.0.d-pre'
|
||||||
|
|
||||||
|
|
||||||
def main(args, seed=None):
|
def main(args, seed=None):
|
||||||
|
|||||||
+31
@@ -715,6 +715,37 @@ def create_dungeon_regions(world, player):
|
|||||||
]
|
]
|
||||||
|
|
||||||
world.initialize_regions()
|
world.initialize_regions()
|
||||||
|
world.get_region('Hera Lobby', player).crystal_switch = True
|
||||||
|
world.get_region('Hera Basement Cage', player).crystal_switch = True
|
||||||
|
world.get_region('Hera Tile Room', player).crystal_switch = True # INTERIOR not accessible (maybe with cane)
|
||||||
|
world.get_region('Hera Tridorm', player).crystal_switch = True
|
||||||
|
world.get_region('Hera Startile Wide', player).crystal_switch = True
|
||||||
|
world.get_region('PoD Arena Main', player).crystal_switch = True
|
||||||
|
world.get_region('PoD Arena Bridge', player).crystal_switch = True
|
||||||
|
world.get_region('PoD Sexy Statue', player).crystal_switch = True
|
||||||
|
world.get_region('PoD Bow Statue', player).crystal_switch = True # LADDER not accessible (maybe with cane)
|
||||||
|
world.get_region('PoD Dark Pegs', player).crystal_switch = True
|
||||||
|
world.get_region('Swamp Crystal Switch', player).crystal_switch = True
|
||||||
|
world.get_region('Thieves Spike Switch', player).crystal_switch = True
|
||||||
|
world.get_region('Ice Bomb Drop', player).crystal_switch = True
|
||||||
|
world.get_region('Ice Conveyor', player).crystal_switch = True
|
||||||
|
world.get_region('Ice Refill', player).crystal_switch = True
|
||||||
|
world.get_region('Mire Fishbone', player).crystal_switch = True
|
||||||
|
world.get_region('Mire Conveyor Crystal', player).crystal_switch = True
|
||||||
|
world.get_region('Mire Tall Dark and Roomy', player).crystal_switch = True
|
||||||
|
world.get_region('Mire Crystal Top', player).crystal_switch = True
|
||||||
|
world.get_region('Mire Falling Foes', player).crystal_switch = True
|
||||||
|
world.get_region('TR Chain Chomps', player).crystal_switch = True
|
||||||
|
world.get_region('TR Pokey 2', player).crystal_switch = True
|
||||||
|
world.get_region('TR Crystaroller', player).crystal_switch = True
|
||||||
|
world.get_region('TR Crystal Maze', player).crystal_switch = True
|
||||||
|
world.get_region('GT Crystal Conveyor', player).crystal_switch = True # INTERIOR not accessible
|
||||||
|
world.get_region('GT Hookshot South Platform', player).crystal_switch = True
|
||||||
|
# world.get_region('GT Double Switch Switches', player).crystal_switch = True # this is not very relevant
|
||||||
|
world.get_region('GT Spike Crystals', player).crystal_switch = True
|
||||||
|
world.get_region('GT Crystal Paths', player).crystal_switch = True
|
||||||
|
world.get_region('GT Hidden Spikes', player).crystal_switch = True
|
||||||
|
world.get_region('GT Crystal Circles', player).crystal_switch = True
|
||||||
|
|
||||||
|
|
||||||
def create_lw_region(player, name, locations=None, exits=None):
|
def create_lw_region(player, name, locations=None, exits=None):
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import struct
|
|||||||
import sys
|
import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from BaseClasses import CollectionState, ShopType, Region, Location, Item, DoorType
|
from BaseClasses import CollectionState, ShopType, Region, Location, DoorType
|
||||||
from DoorShuffle import compass_data
|
from DoorShuffle import compass_data, DROptions
|
||||||
from Dungeons import dungeon_music_addresses
|
from Dungeons import dungeon_music_addresses
|
||||||
from Regions import location_table
|
from Regions import location_table
|
||||||
from Text import MultiByteTextMapper, CompressedTextMapper, text_addresses, Credits, TextTable
|
from Text import MultiByteTextMapper, CompressedTextMapper, text_addresses, Credits, TextTable
|
||||||
@@ -22,7 +22,7 @@ from EntranceShuffle import door_addresses, exit_ids
|
|||||||
|
|
||||||
|
|
||||||
JAP10HASH = '03a63945398191337e896e5771f77173'
|
JAP10HASH = '03a63945398191337e896e5771f77173'
|
||||||
RANDOMIZERBASEHASH = 'c1361fcf13239f8677bacc6f9bc5e9dd'
|
RANDOMIZERBASEHASH = 'c06e14396839bc443a6918e736f1e5a7'
|
||||||
|
|
||||||
|
|
||||||
class JsonRom(object):
|
class JsonRom(object):
|
||||||
@@ -591,7 +591,9 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
patch_shuffled_dark_sanc(world, rom, player)
|
patch_shuffled_dark_sanc(world, rom, player)
|
||||||
|
|
||||||
# patch doors
|
# patch doors
|
||||||
|
dr_flags = DROptions.Eternal_Mini_Bosses
|
||||||
if world.doorShuffle[player] == 'crossed':
|
if world.doorShuffle[player] == 'crossed':
|
||||||
|
rom.write_byte(0x139004, 2)
|
||||||
rom.write_byte(0x151f1, 2)
|
rom.write_byte(0x151f1, 2)
|
||||||
rom.write_byte(0x15270, 2)
|
rom.write_byte(0x15270, 2)
|
||||||
rom.write_byte(0x1597b, 2)
|
rom.write_byte(0x1597b, 2)
|
||||||
@@ -599,6 +601,8 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
update_compasses(rom, world, player)
|
update_compasses(rom, world, player)
|
||||||
else:
|
else:
|
||||||
logging.getLogger('').warning('Randomizer rom update! Compasses in crossed are borken')
|
logging.getLogger('').warning('Randomizer rom update! Compasses in crossed are borken')
|
||||||
|
if world.doorShuffle[player] == 'basic':
|
||||||
|
rom.write_byte(0x139004, 1)
|
||||||
for door in world.doors:
|
for door in world.doors:
|
||||||
if door.dest is not None and door.player == player and door.type in [DoorType.Normal, DoorType.SpiralStairs]:
|
if door.dest is not None and door.player == player and door.type in [DoorType.Normal, DoorType.SpiralStairs]:
|
||||||
rom.write_bytes(door.getAddress(), door.dest.getTarget(door.toggle))
|
rom.write_bytes(door.getAddress(), door.dest.getTarget(door.toggle))
|
||||||
@@ -608,6 +612,11 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
for paired_door in world.paired_doors[player]:
|
for paired_door in world.paired_doors[player]:
|
||||||
rom.write_bytes(paired_door.address_a(world, player), paired_door.rom_data_a(world, player))
|
rom.write_bytes(paired_door.address_a(world, player), paired_door.rom_data_a(world, player))
|
||||||
rom.write_bytes(paired_door.address_b(world, player), paired_door.rom_data_b(world, player))
|
rom.write_bytes(paired_door.address_b(world, player), paired_door.rom_data_b(world, player))
|
||||||
|
for builder in world.dungeon_layouts[player].values():
|
||||||
|
if builder.pre_open_stonewall:
|
||||||
|
if builder.pre_open_stonewall.name == 'Desert Wall Slide NW':
|
||||||
|
dr_flags |= DROptions.Open_Desert_Wall
|
||||||
|
rom.write_byte(0x139006, dr_flags.value)
|
||||||
|
|
||||||
# fix skull woods exit, if not fixed during exit patching
|
# fix skull woods exit, if not fixed during exit patching
|
||||||
if world.fix_skullwoods_exit[player] and world.shuffle[player] == 'vanilla':
|
if world.fix_skullwoods_exit[player] and world.shuffle[player] == 'vanilla':
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ warnpc $279000
|
|||||||
org $279000
|
org $279000
|
||||||
OffsetTable:
|
OffsetTable:
|
||||||
dw -8, 8
|
dw -8, 8
|
||||||
|
DRMode:
|
||||||
|
dw 0
|
||||||
|
DRFlags:
|
||||||
|
dw 0
|
||||||
|
|
||||||
; Vert 0,6,0 Horz 2,0,8
|
; Vert 0,6,0 Horz 2,0,8
|
||||||
org $279010
|
org $279010
|
||||||
|
|||||||
@@ -61,6 +61,14 @@ Palette_SpriteAux1:
|
|||||||
|
|
||||||
org $0DFA53
|
org $0DFA53
|
||||||
jsl.l LampCheckOverride
|
jsl.l LampCheckOverride
|
||||||
|
org $028046 ; <- 10046 - Bank02.asm : 217 (JSL EnableForceBlank) (Start of Module_LoadFile)
|
||||||
|
jsl.l OnFileLoadOverride
|
||||||
|
|
||||||
|
org $05ef47
|
||||||
|
Sprite_HeartContainer_Override: ;sprite_heart_upgrades.asm : 96-100 (LDA $040C : CMP.b #$1A : BNE .not_in_ganons_tower)
|
||||||
|
jsl GtBossHeartCheckOverride : bcs .not_in_ganons_tower
|
||||||
|
nop : stz $0dd0, X : rts
|
||||||
|
.not_in_ganons_tower
|
||||||
|
|
||||||
; These two, if enabled together, have implications for vanilla BK doors in IP/Hera/Mire
|
; These two, if enabled together, have implications for vanilla BK doors in IP/Hera/Mire
|
||||||
; IPBJ is common enough to consider not doing this. Mire is not a concern for vanilla - maybe glitched modes
|
; IPBJ is common enough to consider not doing this. Mire is not a concern for vanilla - maybe glitched modes
|
||||||
|
|||||||
+18
-1
@@ -20,4 +20,21 @@ LampCheckOverride:
|
|||||||
LDA LampConeDarkWorld
|
LDA LampConeDarkWorld
|
||||||
.done
|
.done
|
||||||
;BNE + : STZ $1D : + ; remember to turn cone off after a torch
|
;BNE + : STZ $1D : + ; remember to turn cone off after a torch
|
||||||
RTL
|
RTL
|
||||||
|
|
||||||
|
GtBossHeartCheckOverride:
|
||||||
|
lda $a0 : cmp #$1c : beq ++
|
||||||
|
cmp #$6c : beq ++
|
||||||
|
cmp #$4d : bne +
|
||||||
|
++ lda DRFlags : and #$01 : bne ++ ;skip if flag on
|
||||||
|
lda $403 : ora #$80 : sta $403
|
||||||
|
++ clc
|
||||||
|
rtl
|
||||||
|
+ sec
|
||||||
|
rtl
|
||||||
|
|
||||||
|
OnFileLoadOverride:
|
||||||
|
jsl OnFileLoad ; what I wrote over
|
||||||
|
lda DRFlags : and #$80 : beq + ;flag is off
|
||||||
|
lda $7ef086 : ora #$80 : sta $7ef086
|
||||||
|
+ rtl
|
||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user