Options added for door_type_mode and new partitioned mode

This commit is contained in:
aerinon
2022-07-06 10:06:29 -06:00
parent 2e9d132985
commit d9f0e2a7b6
18 changed files with 722 additions and 258 deletions

View File

@@ -28,6 +28,7 @@ class World(object):
self.shuffle = shuffle.copy()
self.doorShuffle = doorShuffle.copy()
self.intensity = {}
self.door_type_mode = {}
self.logic = logic.copy()
self.mode = mode.copy()
self.swords = swords.copy()
@@ -143,6 +144,7 @@ class World(object):
set_player_attr('colorizepots', False)
set_player_attr('pot_pool', {})
set_player_attr('decoupledoors', False)
set_player_attr('door_type_mode', 'original')
set_player_attr('shopsanity', False)
set_player_attr('mixed_travel', 'prevent')
@@ -1872,7 +1874,6 @@ class Sector(object):
self.item_logic = set()
self.chest_location_set = set()
def region_set(self):
if self.r_name_set is None:
self.r_name_set = dict.fromkeys(map(lambda r: r.name, self.regions))
@@ -2154,7 +2155,7 @@ class Location(object):
def gen_name(self):
name = self.name
world = self.parent_region.world if self.parent_region and self.parent_region.world else None
if self.parent_region.dungeon and world and world.doorShuffle[self.player] == 'crossed':
if self.parent_region.dungeon and world and world.doorShuffle[self.player] not in ['basic', 'vanilla']:
name += f' @ {self.parent_region.dungeon.name}'
if world and world.players > 1:
name += f' ({world.get_player_names(self.player)})'
@@ -2377,6 +2378,8 @@ class Spoiler(object):
'overworld_map': self.world.overworld_map,
'door_shuffle': self.world.doorShuffle,
'intensity': self.world.intensity,
'door_type_mode': self.world.door_type_mode,
'decoupledoors': self.world.decoupledoors,
'dungeon_counters': self.world.dungeon_counters,
'item_pool': self.world.difficulty,
'item_functionality': self.world.difficulty_adjustments,
@@ -2578,6 +2581,7 @@ class Spoiler(object):
outfile.write('Door Shuffle: %s\n' % self.metadata['door_shuffle'][player])
if self.metadata['door_shuffle'][player] != 'vanilla':
outfile.write(f"Intensity: {self.metadata['intensity'][player]}\n")
outfile.write(f"Door Type Mode: {self.metadata['door_type_mode'][player]}\n")
outfile.write(f"Decouple Doors: {yn(self.metadata['decoupledoors'][player])}\n")
outfile.write(f"Experimental: {yn(self.metadata['experimental'][player])}\n")
outfile.write(f"Dungeon Counters: {self.metadata['dungeon_counters'][player]}\n")
@@ -2815,7 +2819,7 @@ class Pot(object):
# byte 0: DDDE EEEE (DR, ER)
dr_mode = {"basic": 1, "crossed": 2, "vanilla": 0}
dr_mode = {"basic": 1, "crossed": 2, "vanilla": 0, "partitioned": 3}
er_mode = {"vanilla": 0, "simple": 1, "restricted": 2, "full": 3, "crossed": 4, "insanity": 5, 'lite': 8,
'lean': 9, "dungeonsfull": 7, "dungeonssimple": 6}
@@ -2845,7 +2849,8 @@ counter_mode = {"default": 0, "off": 1, "on": 2, "pickup": 3}
# byte 6: CCCC CPAA (crystals ganon, pyramid, access
access_mode = {"items": 0, "locations": 1, "none": 2}
# byte 7: BSMC ??EE (big, small, maps, compass, bosses, enemies)
# byte 7: BSMC DDEE (big, small, maps, compass, door_type, enemies)
door_type_mode = {'original': 0, 'big': 1, 'all': 2, 'chaos': 3}
enemy_mode = {"none": 0, "shuffled": 1, "chaos": 2, "random": 2, "legacy": 3}
# byte 8: HHHD DPBS (enemy_health, enemy_dmg, potshuffle, bomb logic, shuffle links)
@@ -2898,7 +2903,7 @@ class Settings(object):
(0x80 if w.bigkeyshuffle[p] else 0) | (0x40 if w.keyshuffle[p] else 0)
| (0x20 if w.mapshuffle[p] else 0) | (0x10 if w.compassshuffle[p] else 0)
| (enemy_mode[w.enemy_shuffle[p]]),
| (door_type_mode[w.door_type_mode[p]] << 2) | (enemy_mode[w.enemy_shuffle[p]]),
(e_health[w.enemy_health[p]] << 5) | (e_dmg[w.enemy_damage[p]] << 3) | (0x4 if w.potshuffle[p] else 0)
| (0x2 if w.bombbag[p] else 0) | (1 if w.shufflelinks[p] else 0),
@@ -2955,7 +2960,7 @@ class Settings(object):
args.keyshuffle[p] = True if settings[7] & 0x40 else False
args.mapshuffle[p] = True if settings[7] & 0x20 else False
args.compassshuffle[p] = True if settings[7] & 0x10 else False
# args.shufflebosses[p] = r(boss_mode)[(settings[7] & 0xc) >> 2]
args.door_type_mode[p] = r(door_type_mode)[(settings[7] & 0xc) >> 2]
args.shuffleenemies[p] = r(enemy_mode)[settings[7] & 0x3]
args.enemy_health[p] = r(e_health)[(settings[8] & 0xE0) >> 5]

3
CLI.py
View File

@@ -125,7 +125,7 @@ def parse_cli(argv, no_defaults=False):
'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor',
'heartbeep', 'remote_items', 'shopsanity', 'dropshuffle', 'pottery', 'keydropshuffle',
'mixed_travel', 'standardize_palettes', 'code', 'reduce_flashing', 'shuffle_sfx',
'msu_resume', 'collection_rate', 'colorizepots', 'decoupledoors']:
'msu_resume', 'collection_rate', 'colorizepots', 'decoupledoors', 'door_type_mode']:
value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name)
if player == 1:
setattr(ret, name, {1: value})
@@ -192,6 +192,7 @@ def parse_settings():
"keysanity": False,
"door_shuffle": "basic",
"intensity": 2,
'door_type_mode': 'original',
'decoupledoors': False,
"experimental": False,
"dungeon_counters": "default",

File diff suppressed because it is too large Load Diff

View File

@@ -808,6 +808,7 @@ class ExplorationState(object):
self.prize_door_set = {}
self.prize_doors = []
self.prize_doors_opened = False
self.prize_received = False
def copy(self):
ret = ExplorationState(dungeon=self.dungeon)
@@ -839,6 +840,7 @@ class ExplorationState(object):
ret.prize_door_set = dict(self.prize_door_set)
ret.prize_doors = list(self.prize_doors)
ret.prize_doors_opened = self.prize_doors_opened
ret.prize_received = self.prize_received
return ret
def next_avail_door(self):
@@ -984,6 +986,20 @@ class ExplorationState(object):
elif not self.in_door_list(door, self.avail_doors):
self.append_door_to_list(door, self.avail_doors)
def add_all_doors_check_big_keys(self, region, big_key_door_proposal, world, player):
for door in get_doors(world, region, player):
if self.can_traverse(door):
if door.controller:
door = door.controller
if (door in big_key_door_proposal or door.name in special_big_key_doors) and not self.big_key_opened:
if not self.in_door_list(door, self.big_doors):
self.append_door_to_list(door, self.big_doors)
elif door.req_event is not None and door.req_event not in self.events:
if not self.in_door_list(door, self.event_doors):
self.append_door_to_list(door, self.event_doors)
elif not self.in_door_list(door, self.avail_doors):
self.append_door_to_list(door, self.avail_doors)
def visited(self, region):
if self.crystal == CrystalBarrier.Either:
return region in self.visited_blue and region in self.visited_orange
@@ -1213,6 +1229,8 @@ class DungeonBuilder(object):
self.combo_size = None
self.flex = 0
self.key_door_proposal = None
self.bk_door_proposal = None
self.trap_door_proposal = None
self.allowance = None
if 'Stonewall' in name:
@@ -1279,9 +1297,7 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, dunge
dungeon_map = {}
for key in dungeon_pool:
dungeon_map[key] = DungeonBuilder(key)
for key in dungeon_boss_sectors.keys():
current_dungeon = dungeon_map[key]
current_dungeon = dungeon_map[key] = DungeonBuilder(key)
for r_name in dungeon_boss_sectors[key]:
assign_sector(find_sector(r_name, candidate_sectors), current_dungeon, candidate_sectors, global_pole)
if key == 'Hyrule Castle' and world.mode[player] == 'standard':
@@ -1293,7 +1309,7 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, dunge
candidate_sectors, global_pole)
entrances_map, potentials, connections = connections_tuple
accessible_sectors, reverse_d_map = set(), {}
for key in dungeon_entrances.keys():
for key in dungeon_pool:
current_dungeon = dungeon_map[key]
current_dungeon.all_entrances = dungeon_entrances[key]
for r_name in current_dungeon.all_entrances:
@@ -1419,6 +1435,8 @@ def identify_destination_sectors(accessible_sectors, reverse_d_map, dungeon_map,
if ent_name in found_connections:
continue
sector = find_sector(ent_name, reverse_d_map.keys())
if sector is None:
continue
if sector in accessible_sectors:
found_connections.add(ent_name)
accessible_overworld.add(region) # todo: drops don't give ow access

View File

@@ -248,7 +248,7 @@ def find_all_locations(sector):
def calc_max_chests(builder, key_layout, world, player):
if world.doorShuffle[player] != 'crossed':
if world.doorShuffle[player] in ['basic', 'vanilla']:
return len(world.get_dungeon(key_layout.sector.name, player).small_keys)
return max(0, builder.key_doors_num - key_layout.max_drops)
@@ -1169,6 +1169,16 @@ def expand_key_state(state, flat_proposal, world, player):
state.add_all_doors_check_keys(connect_region, flat_proposal, world, player)
def expand_big_key_state(state, flat_proposal, world, player):
while len(state.avail_doors) > 0:
exp_door = state.next_avail_door()
door = exp_door.door
connect_region = world.get_entrance(door.name, player).connected_region
if state.validate(door, connect_region, world, player):
state.visit_region(connect_region, key_checks=True)
state.add_all_doors_check_big_keys(connect_region, flat_proposal, world, player)
def flatten_pair_list(paired_list):
flat_list = []
for d in paired_list:
@@ -1398,6 +1408,42 @@ def prize_relevance(key_layout, dungeon_entrance):
return None
def prize_relevance_sig2(start_regions, d_name, dungeon_entrance):
if len(start_regions) > 1 and dungeon_entrance and dungeon_table[d_name].prize:
if dungeon_entrance.name in ['Ganons Tower', 'Inverted Ganons Tower']:
return 'GT'
elif dungeon_entrance.name == 'Pyramid Fairy':
return 'BigBomb'
return None
def validate_bk_layout(proposal, builder, start_regions, world, player):
bk_special = check_bk_special(builder.master_sector.regions, world, player)
if world.bigkeyshuffle[player] and (world.dropshuffle[player] or not bk_special):
return True
flat_proposal = flatten_pair_list(proposal)
state = ExplorationState(dungeon=builder.name)
state.big_key_special = bk_special
for region in start_regions:
dungeon_entrance, portal_door = find_outside_connection(region)
prize_relevant_flag = prize_relevance_sig2(start_regions, builder.name, dungeon_entrance)
if prize_relevant_flag:
state.append_door_to_list(portal_door, state.prize_doors)
state.prize_door_set[portal_door] = dungeon_entrance
# key_layout.prize_relevant = prize_relevant_flag
else:
state.visit_region(region, key_checks=True)
state.add_all_doors_check_big_keys(region, flat_proposal, world, player)
expand_big_key_state(state, flat_proposal, world, player)
if bk_special:
for loc in state.found_locations:
if loc.forced_big_key():
return True
else:
return len(state.bk_found) > 0
return False
# Soft lock stuff
def validate_key_layout(key_layout, world, player):
# retro is all good - except for hyrule castle in standard mode
@@ -1601,7 +1647,7 @@ def create_key_counters(key_layout, world, player):
state.key_locations = len(builder.key_door_proposal) - builder.key_drop_cnt
else:
builder = world.dungeon_layouts[player][key_layout.sector.name]
state.key_locations = builder.total_keys - builder.key_drop_cnt
state.key_locations = max(0, builder.total_keys - builder.key_drop_cnt)
state.big_key_special = False
for region in key_layout.sector.regions:
for location in region.locations:

View File

@@ -106,6 +106,7 @@ def main(args, seed=None, fish=None):
world.enemy_damage = args.enemy_damage.copy()
world.beemizer = args.beemizer.copy()
world.intensity = {player: random.randint(1, 3) if args.intensity[player] == 'random' else int(args.intensity[player]) for player in range(1, world.players + 1)}
world.door_type_mode = args.door_type_mode.copy()
world.experimental = args.experimental.copy()
world.dungeon_counters = args.dungeon_counters.copy()
world.fish = fish

31
Rom.py
View File

@@ -37,7 +37,7 @@ from source.dungeon.RoomList import Room0127
JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = 'add982e935888df04ddfa570bc07bede'
RANDOMIZERBASEHASH = 'afcd895b87559cd29b04aa3714cbc929'
class JsonRom(object):
@@ -738,11 +738,11 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
# setup dr option flags based on experimental, etc.
dr_flags = DROptions.Eternal_Mini_Bosses if world.doorShuffle[player] == 'vanilla' else DROptions.Town_Portal
if world.doorShuffle[player] == 'crossed':
if world.doorShuffle[player] not in ['vanilla', 'basic']:
dr_flags |= DROptions.Map_Info
if world.collection_rate[player] and world.goal[player] not in ['triforcehunt', 'trinity']:
dr_flags |= DROptions.Debug
if world.doorShuffle[player] == 'crossed' and world.logic[player] != 'nologic'\
if world.doorShuffle[player] not in ['vanilla', 'basic'] and world.logic[player] != 'nologic'\
and world.mixed_travel[player] == 'prevent':
# PoD Falling Bridge or Hammjump
# 1FA607: db $2D, $79, $69 ; 0x0069: Vertical Rail ↕ | { 0B, 1E } | Size: 05
@@ -763,6 +763,8 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
dr_flags |= DROptions.DarkWorld_Spawns
if world.logic[player] != 'nologic':
dr_flags |= DROptions.Fix_EG
if world.door_type_mode in ['big', 'chaos']:
dr_flags |= DROptions.BigKeyDoor_Shuffle
my_locations = world.get_filled_locations(player)
valid_locations = [l for l in my_locations if ((l.type == LocationType.Pot and not l.forced_item)
@@ -772,7 +774,8 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
valid_loc_by_dungeon = valid_dungeon_locations(valid_locations)
# fix hc big key problems (map and compass too)
if world.doorShuffle[player] == 'crossed' or world.dropshuffle[player] or world.pottery[player] not in ['none', 'cave']:
if (world.doorShuffle[player] not in ['vanilla', 'basic'] or world.dropshuffle[player]
or world.pottery[player] not in ['none', 'cave']):
rom.write_byte(0x151f1, 2)
rom.write_byte(0x15270, 2)
sanctuary = world.get_region('Sanctuary', player)
@@ -800,7 +803,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
rom.write_bytes(0x13fff4, [0xe4, 0x00])
# patch doors
if world.doorShuffle[player] == 'crossed':
if world.doorShuffle[player] not in ['vanilla', 'basic']:
rom.write_byte(0x138002, 2)
for name, layout in world.key_layout[player].items():
offset = compass_data[name][4]//2
@@ -1377,7 +1380,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
if len(portal_list) == 1:
portal_idx = 0
else:
if world.doorShuffle[player] == 'crossed':
if world.doorShuffle[player] not in ['vanilla', 'basic']:
# the random choice excludes sanctuary
portal_idx = next((i for i, elem in enumerate(portal_list)
if world.get_portal(elem, player).chosen), random.choice([1, 2, 3]))
@@ -1392,7 +1395,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
rom.write_bytes(0x53E56+ow_map_index*2, int16_as_bytes(coords[1]))
rom.write_byte(0x53EA6+ow_map_index, world_indicator)
# in crossed doors - flip the compass exists flags
if world.doorShuffle[player] == 'crossed':
if world.doorShuffle[player] not in ['vanilla', 'basic']:
for dungeon, portal_list in dungeon_portals.items():
ow_map_index = dungeon_table[dungeon].map_index
exists_flag = any(x for x in world.get_dungeon(dungeon, player).dungeon_items if x.type == 'Compass')
@@ -1495,7 +1498,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
rom.write_bytes(0x180188, [0x20, 0, 0]) # Zelda respawn refills (magic, bombs, arrows)
rom.write_bytes(0x18018B, [0x20, 0, 0]) # Mantle respawn refills (magic, bombs, arrows)
magic_max, magic_small = 0x80, 0x20
if world.doorShuffle[player] == 'crossed':
if world.doorShuffle[player] not in ['vanilla', 'basic']:
# Uncle respawn refills (magic, bombs, arrows)
rom.write_bytes(0x180185, [max(0x20, magic_max), max(3, bomb_max), max(10, bow_max)])
rom.write_bytes(0x180188, [0x20, 3, 10]) # Zelda respawn refills (magic, bombs, arrows)
@@ -2081,13 +2084,13 @@ def write_strings(rom, world, player, team):
# Next we write a few hints for specific inconvenient locations. We don't make many because in entrance this is highly unpredictable.
locations_to_hint = InconvenientLocations.copy()
if world.doorShuffle[player] != 'crossed':
if world.doorShuffle[player] == 'vanilla':
locations_to_hint.extend(InconvenientDungeonLocations)
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull']:
locations_to_hint.extend(InconvenientVanillaLocations)
random.shuffle(locations_to_hint)
hint_count = 3 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 5
hint_count -= 2 if world.doorShuffle[player] == 'crossed' else 0
hint_count -= 2 if world.doorShuffle[player] not in ['vanilla', 'basic'] else 0
del locations_to_hint[hint_count:]
for location in locations_to_hint:
if location == 'Swamp Left':
@@ -2150,7 +2153,7 @@ def write_strings(rom, world, player, team):
items_to_hint.extend(BigKeys)
random.shuffle(items_to_hint)
hint_count = 5 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 8
hint_count += 2 if world.doorShuffle[player] == 'crossed' else 0
hint_count += 2 if world.doorShuffle[player] not in ['vanilla', 'basic'] else 0
while hint_count > 0 and len(items_to_hint) > 0:
this_item = items_to_hint.pop(0)
this_location = world.find_items_not_key_only(this_item, player)
@@ -2163,8 +2166,8 @@ def write_strings(rom, world, player, team):
tt[hint_locations.pop(0)] = this_hint
hint_count -= 1
# Adding a hint for the Thieves' Town Attic location in Crossed door shuffle.
if world.doorShuffle[player] in ['crossed']:
# Adding a hint for the Thieves' Town Attic location in mixed door shuffles.
if world.doorShuffle[player] not in ['vanilla', 'basic']:
attic_hint = world.get_location("Thieves' Town - Attic", player).parent_region.dungeon.name
this_hint = 'A cracked floor can be found in ' + attic_hint + '.'
if world.intensity[player] < 2 and hint_locations[0] == 'telepathic_tile_thieves_town_upstairs':
@@ -2324,7 +2327,7 @@ def write_strings(rom, world, player, team):
tt['tablet_bombos_book'] = bombos_text
# attic hint
if world.doorShuffle[player] in ['crossed']:
if world.doorShuffle[player] not in ['vanilla', 'basic']:
attic_hint = world.get_location("Thieves' Town - Attic", player).parent_region.dungeon.name
tt['blind_not_that_way'] = f'{attic_hint} is too bright for my eyes'
# see tagalog.asm tables at 957,967 or Follower_HandleTrigger in JPDASM

View File

@@ -395,8 +395,8 @@ class DoorKind(Enum):
Bombable = 0x2E
BlastWall = 0x30
Hidden = 0x32
TrapTriggerable = 0x36 # right side trap or south side trap (West, South)
Trap2 = 0x38 # left side trap or north side trap (East, North)
TrapTriggerable = 0x36 # right side trap or bottom side trap (West, North)
Trap2 = 0x38 # left side trap or top side trap (East, South)
NormalLow2 = 0x40
TrapTriggerableLow = 0x44
Warp = 0x46

Binary file not shown.

View File

@@ -17,6 +17,11 @@
1: 2
2: 2
3: 4
door_type_mode:
original: 2
big: 2
all: 1
chaos: 1
decoupledoors: off
dropshuffle:
on: 1

View File

@@ -155,6 +155,7 @@
"door_shuffle": {
"choices": [
"basic",
"partitioned",
"crossed",
"vanilla"
]
@@ -164,7 +165,15 @@
"3", "2", "1", "random"
]
},
"deoupledoors": {
"door_type_mode": {
"choices":[
"original",
"big",
"all",
"chaos"
]
},
"decoupledoors": {
"action": "store_true",
"type": "bool"
},

View File

@@ -205,6 +205,7 @@
"door_shuffle": [
"Select Door Shuffling Algorithm. (default: %(default)s)",
"Basic: Doors are mixed within a single dungeon.",
"Partitioned Doors are mixed in 3 partitions: L1-3+HC+AT, D1-4, D5-8",
"Crossed: Doors are mixed between all dungeons.",
"Vanilla: All doors are connected the same way they were in the",
" base game."
@@ -216,6 +217,13 @@
"3: And shuffles dungeon lobbies",
"random: Picks one of those at random"
],
"door_type_mode" : [
"Door Types to Shuffle (default: %(default)s)",
"original: Shuffles key doors, bombable, and dashable doors",
"big: Adds big key doors",
"all: Adds traps doors (and any future supported door types)",
"chaos: Increases the number of door types in all dungeon pools"
],
"decoupledoors" : [ "Door entrances and exits are decoupled" ],
"experimental": [ "Enable experimental features. (default: %(default)s)" ],
"dungeon_counters": [ "Enable dungeon chest counters. (default: %(default)s)" ],

View File

@@ -73,6 +73,7 @@
"randomizer.dungeon.dungeondoorshuffle": "Dungeon Door Shuffle",
"randomizer.dungeon.dungeondoorshuffle.vanilla": "Vanilla",
"randomizer.dungeon.dungeondoorshuffle.basic": "Basic",
"randomizer.dungeon.dungeondoorshuffle.partitioned": "Partitioned",
"randomizer.dungeon.dungeondoorshuffle.crossed": "Crossed",
"randomizer.dungeon.dungeonintensity": "Intensity Level",
@@ -81,6 +82,12 @@
"randomizer.dungeon.dungeonintensity.3": "3: Dungeon Lobbies",
"randomizer.dungeon.dungeonintensity.random": "Random",
"randomizer.dungeon.door_type_mode": "Door Types to Shuffle",
"randomizer.dungeon.door_type_mode.original": "Small Key Doors, Bomb Doors, Dash Doors",
"randomizer.dungeon.door_type_mode.big": "Adds Big Key Doors",
"randomizer.dungeon.door_type_mode.all": "Adds Trap Doors",
"randomizer.dungeon.door_type_mode.chaos": "Increases all door types",
"randomizer.dungeon.experimental": "Enable Experimental Features",
"randomizer.dungeon.dungeon_counters": "Dungeon Chest Counters",

View File

@@ -6,6 +6,7 @@
"options": [
"vanilla",
"basic",
"partitioned",
"crossed"
]
},
@@ -22,6 +23,19 @@
"width": 45
}
},
"door_type_mode": {
"type": "selectbox",
"default": "basic",
"options": [
"original",
"big",
"all",
"chaos"
],
"config": {
"width": 45
}
},
"decoupledoors": { "type": "checkbox" },
"keydropshuffle": { "type": "checkbox" },
"pottery": {

View File

@@ -87,6 +87,7 @@ class CustomSettings(object):
args.standardize_palettes[p] = get_setting(settings['standardize_palettes'],
args.standardize_palettes[p])
args.intensity[p] = get_setting(settings['intensity'], args.intensity[p])
args.door_type_mode[p] = get_setting(settings['door_type_mode'], args.door_type_mode[p])
args.decoupledoors[p] = get_setting(settings['decoupledoors'], args.decoupledoors[p])
args.dungeon_counters[p] = get_setting(settings['dungeon_counters'], args.dungeon_counters[p])
args.crystals_gt[p] = get_setting(settings['crystals_gt'], args.crystals_gt[p])
@@ -182,6 +183,7 @@ class CustomSettings(object):
settings_dict[p]['shuffle'] = world.shuffle[p]
settings_dict[p]['door_shuffle'] = world.doorShuffle[p]
settings_dict[p]['intensity'] = world.intensity[p]
settings_dict[p]['door_type_mode'] = world.door_type_mode[p]
settings_dict[p]['decoupledoors'] = world.decoupledoors[p]
settings_dict[p]['logic'] = world.logic[p]
settings_dict[p]['mode'] = world.mode[p]

View File

@@ -95,6 +95,7 @@ SETTINGSTOPROCESS = {
"bigkeyshuffle": "bigkeyshuffle",
"dungeondoorshuffle": "door_shuffle",
"dungeonintensity": "intensity",
"door_type_mode": "door_type_mode",
"decoupledoors": "decoupledoors",
"keydropshuffle": "keydropshuffle",
"dropshuffle": "dropshuffle",

View File

@@ -135,9 +135,9 @@ def create_random_proposal(doors_to_connect, world, player):
proposal[secondary_door] = primary_door
primary_bucket[opp_hook].remove(secondary_door)
secondary_bucket[next_hook].remove(primary_door)
logger.debug(f'Linking {primary_door.name} <-> {secondary_door.name}')
logger.debug(f' Linking {primary_door.name} <-> {secondary_door.name}')
else:
logger.debug(f'Linking {primary_door.name} -> {secondary_door.name}')
logger.debug(f' Linking {primary_door.name} -> {secondary_door.name}')
def decouple_check(primary_list, secondary_list, primary_door, secondary_door, world, player):
@@ -203,11 +203,11 @@ def modify_proposal(proposed_map, explored_state, doors_to_connect, hash_code_se
itr += 1
if not world.decoupledoors[player]:
logger.debug(f'Re-linking {attempt.name} <-> {new_door.name}')
logger.debug(f'Re-linking {old_attempt.name} <-> {old_target.name}')
logger.debug(f' Re-linking {attempt.name} <-> {new_door.name}')
logger.debug(f' Re-linking {old_attempt.name} <-> {old_target.name}')
else:
logger.debug(f'Re-Linking {attempt.name} -> {new_door.name}')
logger.debug(f'Re-Linking {old_attempt.name} -> {old_target.name}')
logger.debug(f' Re-Linking {attempt.name} -> {new_door.name}')
logger.debug(f' Re-Linking {old_attempt.name} -> {old_target.name}')
hash_code_set.add(hash_code)
return proposed_map, hash_code
@@ -349,12 +349,7 @@ def connect_doors(a, b):
return
# Connect supported types
if a.type in [DoorType.Normal, DoorType.SpiralStairs, DoorType.Open, DoorType.StraightStairs, DoorType.Ladder]:
if a.blocked:
connect_one_way(b.entrance, a.entrance)
elif b.blocked:
connect_one_way(a.entrance, b.entrance)
else:
connect_two_way(a.entrance, b.entrance)
connect_two_way(a.entrance, b.entrance)
dep_doors, target = [], None
if len(a.dependents) > 0:
dep_doors, target = a.dependents, b
@@ -527,7 +522,7 @@ class ExplorationState(object):
self.key_locations += 1
if location.name not in dungeon_events and '- Prize' not in location.name and location.name not in ['Agahnim 1', 'Agahnim 2']:
self.ttl_locations += 1
if location not in self.found_locations: # todo: special logic for TT Boss?
if location not in self.found_locations:
self.found_locations.append(location)
if not bk_flag:
self.bk_found.add(location)
@@ -616,7 +611,7 @@ class ExplorationState(object):
elif not self.in_door_list(door, self.avail_doors):
self.append_door_to_list(door, self.avail_doors, flag)
def add_all_doors_check_proposed_2(self, region, proposed_map, valid_doors, flag, world, player):
def add_all_doors_check_proposed_2(self, region, proposed_map, valid_doors, world, player):
for door in get_doors(world, region, player):
if door in proposed_map and door.name in valid_doors:
self.visited_doors.add(door)
@@ -625,16 +620,16 @@ class ExplorationState(object):
door = door.controller
if door.dest is None and door not in proposed_map.keys() and door.name in valid_doors:
if not self.in_door_list_ic(door, self.unattached_doors):
self.append_door_to_list(door, self.unattached_doors, flag)
self.append_door_to_list(door, self.unattached_doors)
else:
other = self.find_door_in_list(door, self.unattached_doors)
if self.crystal != other.crystal:
other.crystal = CrystalBarrier.Either
elif door.req_event is not None and door.req_event not in self.events and not self.in_door_list(door,
self.event_doors):
self.append_door_to_list(door, self.event_doors, flag)
self.append_door_to_list(door, self.event_doors)
elif not self.in_door_list(door, self.avail_doors):
self.append_door_to_list(door, self.avail_doors, flag)
self.append_door_to_list(door, self.avail_doors)
def add_all_doors_check_proposed_traps(self, region, proposed_traps, world, player):
for door in get_doors(world, region, player):

View File

@@ -77,6 +77,7 @@ def roll_settings(weights):
door_shuffle = get_choice('door_shuffle')
ret.door_shuffle = door_shuffle if door_shuffle != 'none' else 'vanilla'
ret.intensity = get_choice('intensity')
ret.door_type_mode = get_choice('door_type_mode')
ret.decoupledoors = get_choice('decoupledoors') == 'on'
ret.experimental = get_choice('experimental') == 'on'
ret.collection_rate = get_choice('collection_rate') == 'on'