Merge branch 'DoorDevUnstable' into DoorDevVolatile

# Conflicts:
#	CLI.py
#	Main.py
#	RELEASENOTES.md
#	Rom.py
#	Rules.py
#	data/base2current.bps
#	source/classes/CustomSettings.py
#	source/tools/MysteryUtils.py
This commit is contained in:
aerinon
2023-09-29 11:44:23 -06:00
25 changed files with 516 additions and 157 deletions

View File

@@ -78,6 +78,7 @@ class World(object):
self.rooms = []
self._room_cache = {}
self.dungeon_layouts = {}
self.dungeon_pool = {}
self.inaccessible_regions = {}
self.enabled_entrances = {}
self.key_logic = {}
@@ -145,6 +146,7 @@ class World(object):
set_player_attr('colorizepots', True)
set_player_attr('pot_pool', {})
set_player_attr('decoupledoors', False)
set_player_attr('door_self_loops', False)
set_player_attr('door_type_mode', 'original')
set_player_attr('trap_door_mode', 'optional')
set_player_attr('key_logic_algorithm', 'default')
@@ -1764,6 +1766,7 @@ class Door(object):
self.dest = None
self.blocked = False # Indicates if the door is normally blocked off as an exit. (Sanc door or always closed)
self.blocked_orig = False
self.trapped = False
self.stonewall = False # Indicate that the door cannot be enter until exited (Desert Torches, PoD Eye Statue)
self.smallKey = False # There's a small key door on this side
self.bigKey = False # There's a big key door on this side
@@ -1874,7 +1877,7 @@ class Door(object):
return self
def no_exit(self):
self.blocked = self.blocked_orig = True
self.blocked = self.blocked_orig = self.trapped = True
return self
def no_entrance(self):
@@ -2483,6 +2486,7 @@ class Spoiler(object):
'trap_door_mode': self.world.trap_door_mode,
'key_logic': self.world.key_logic_algorithm,
'decoupledoors': self.world.decoupledoors,
'door_self_loops': self.world.door_self_loops,
'dungeon_counters': self.world.dungeon_counters,
'item_pool': self.world.difficulty,
'item_functionality': self.world.difficulty_adjustments,
@@ -2512,7 +2516,9 @@ class Spoiler(object):
'triforcegoal': self.world.treasure_hunt_count,
'triforcepool': self.world.treasure_hunt_total,
'race': self.world.settings.world_rep['meta']['race'],
'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)}
'user_notes': self.world.settings.world_rep['meta']['user_notes'],
'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)},
'seed': self.world.seed
}
for p in range(1, self.world.players + 1):
@@ -2653,6 +2659,8 @@ class Spoiler(object):
self.parse_meta()
with open(filename, 'w') as outfile:
outfile.write('ALttP Dungeon Randomizer Version %s - Seed: %s\n\n' % (self.metadata['version'], self.world.seed))
if self.metadata['user_notes']:
outfile.write('User Notes: %s\n' % self.metadata['user_notes'])
outfile.write('Filling Algorithm: %s\n' % self.world.algorithm)
outfile.write('Players: %d\n' % self.world.players)
outfile.write('Teams: %d\n' % self.world.teams)
@@ -2694,6 +2702,7 @@ class Spoiler(object):
outfile.write(f"Trap Door Mode: {self.metadata['trap_door_mode'][player]}\n")
outfile.write(f"Key Logic Algorithm: {self.metadata['key_logic'][player]}\n")
outfile.write(f"Decouple Doors: {yn(self.metadata['decoupledoors'][player])}\n")
outfile.write(f"Spiral Stairs can self-loop: {yn(self.metadata['door_self_loops'][player])}\n")
outfile.write(f"Experimental: {yn(self.metadata['experimental'][player])}\n")
outfile.write(f"Dungeon Counters: {self.metadata['dungeon_counters'][player]}\n")
outfile.write(f"Drop Shuffle: {self.metadata['dropshuffle'][player]}\n")
@@ -2952,7 +2961,7 @@ class Pot(object):
# byte 0: DDDE EEEE (DR, ER)
dr_mode = {"basic": 1, "crossed": 2, "vanilla": 0, "partitioned": 3}
dr_mode = {"basic": 1, "crossed": 2, "vanilla": 0, "partitioned": 3, 'paired': 4}
er_mode = {"vanilla": 0, "simple": 1, "restricted": 2, "full": 3, "crossed": 4, "insanity": 5, 'lite': 8,
'lean': 9, "dungeonsfull": 7, "dungeonssimple": 6}
@@ -2978,10 +2987,10 @@ drop_shuffle_mode = {'none': 0, 'keys': 1, 'underworld': 2}
pottery_mode = {'none': 0, 'keys': 2, 'lottery': 3, 'dungeon': 4, 'cave': 5, 'cavekeys': 6, 'reduced': 7,
'clustered': 8, 'nonempty': 9}
# byte 5: CCCC CTTX (crystals gt, ctr2, experimental)
# byte 5: SCCC CTTX (self-loop doors, crystals gt, ctr2, experimental)
counter_mode = {"default": 0, "off": 1, "on": 2, "pickup": 3}
# byte 6: CCCC CPAA (crystals ganon, pyramid, access
# byte 6: ?CCC CPAA (crystals ganon, pyramid, access
access_mode = {"items": 0, "locations": 1, "none": 2}
# byte 7: B?MC DDEE (big, ?, maps, compass, door_type, enemies)
@@ -3039,7 +3048,8 @@ class Settings(object):
(0x80 if w.shuffletavern[p] else 0) | (drop_shuffle_mode[w.dropshuffle[p]] << 4) | (pottery_mode[w.pottery[p]]),
((8 if w.crystals_gt_orig[p] == "random" else int(w.crystals_gt_orig[p])) << 3)
(0x80 if w.door_self_loops[p] else 0)
| ((8 if w.crystals_gt_orig[p] == "random" else int(w.crystals_gt_orig[p])) << 3)
| (counter_mode[w.dungeon_counters[p]] << 1) | (1 if w.experimental[p] else 0),
((8 if w.crystals_ganon_orig[p] == "random" else int(w.crystals_ganon_orig[p])) << 3)
@@ -3059,8 +3069,8 @@ class Settings(object):
(flute_mode[w.flute_mode[p]] << 7 | bow_mode[w.bow_mode[p]] << 4
| take_any_mode[w.take_any[p]] << 2 | keyshuffle_mode[w.keyshuffle[p]]),
((0x80 if w.pseudoboots[p] else 0) | overworld_map_mode[w.overworld_map[p]] << 6
| trap_door_mode[w.trap_door_mode[p]] << 4 | key_logic_algo[w.key_logic_algorithm[p]]),
((0x80 if w.pseudoboots[p] else 0) | overworld_map_mode[w.overworld_map[p]] << 5
| trap_door_mode[w.trap_door_mode[p]] << 3 | key_logic_algo[w.key_logic_algorithm[p]]),
])
return base64.b64encode(code, "+-".encode()).decode()
@@ -3098,12 +3108,13 @@ class Settings(object):
args.dropshuffle[p] = r(drop_shuffle_mode)[(settings[4] & 0x70) >> 4]
args.pottery[p] = r(pottery_mode)[settings[4] & 0x0F]
args.door_self_loops[p] = True if settings[5] & 0x80 else False
args.dungeon_counters[p] = r(counter_mode)[(settings[5] & 0x6) >> 1]
cgt = (settings[5] & 0xf8) >> 3
cgt = (settings[5] & 0x78) >> 3
args.crystals_gt[p] = "random" if cgt == 8 else cgt
args.experimental[p] = True if settings[5] & 0x1 else False
cgan = (settings[6] & 0xf8) >> 3
cgan = (settings[6] & 0x78) >> 3
args.crystals_ganon[p] = "random" if cgan == 8 else cgan
args.openpyramid[p] = True if settings[6] & 0x4 else False
@@ -3130,8 +3141,8 @@ class Settings(object):
args.keyshuffle[p] = r(keyshuffle_mode)[settings[11] & 0x3]
if len(settings) > 12:
args.pseudoboots[p] = True if settings[12] & 0x80 else False
args.overworld_map[p] = r(overworld_map_mode)[(settings[12] & 0x60) >> 6]
args.trap_door_mode[p] = r(trap_door_mode)[(settings[12] & 0x14) >> 4]
args.overworld_map[p] = r(overworld_map_mode)[(settings[12] & 0x60) >> 5]
args.trap_door_mode[p] = r(trap_door_mode)[(settings[12] & 0x18) >> 3]
args.key_logic_algorithm[p] = r(key_logic_algo)[settings[12] & 0x07]