Merge remote-tracking branch 'origin/DoorDev' into DoorDev

This commit is contained in:
aerinon
2020-03-07 09:10:02 -07:00
11 changed files with 32 additions and 40 deletions

View File

@@ -41,7 +41,7 @@ class World(object):
self.shuffle_bonk_prizes = False self.shuffle_bonk_prizes = False
self.light_world_light_cone = False self.light_world_light_cone = False
self.dark_world_light_cone = False self.dark_world_light_cone = False
self.clock_mode = 'off' self.clock_mode = 'none'
self.rupoor_cost = 10 self.rupoor_cost = 10
self.aga_randomness = True self.aga_randomness = True
self.lock_aga_door_in_escape = False self.lock_aga_door_in_escape = False

4
CLI.py
View File

@@ -188,7 +188,7 @@ def parse_arguments(argv, no_defaults=False):
base game. base game.
''') ''')
parser.add_argument('--experimental', default=defval(settings["experimental"] != 0), help='Enable experimental features', action='store_true') parser.add_argument('--experimental', default=defval(settings["experimental"] != 0), help='Enable experimental features', action='store_true')
parser.add_argument('--dungeon_counters', default=defval(settings["dungeon_counters"]), help='Enable dungeon chest counters', const='off', nargs='?', choices=['off', 'on', 'pickup']) parser.add_argument('--dungeon_counters', default=defval(settings["dungeon_counters"]), help='Enable dungeon chest counters', const='off', nargs='?', choices=['off', 'on', 'pickup', 'default'])
parser.add_argument('--crystals_ganon', default=defval(settings["crystals_ganon"]), const='7', nargs='?', choices=['random', '0', '1', '2', '3', '4', '5', '6', '7'], parser.add_argument('--crystals_ganon', default=defval(settings["crystals_ganon"]), const='7', nargs='?', choices=['random', '0', '1', '2', '3', '4', '5', '6', '7'],
help='''\ help='''\
How many crystals are needed to defeat ganon. Any other How many crystals are needed to defeat ganon. Any other
@@ -358,7 +358,7 @@ def get_settings():
"keysanity": False, "keysanity": False,
"door_shuffle": "basic", "door_shuffle": "basic",
"experimental": 0, "experimental": 0,
"dungeon_counters": "off", "dungeon_counters": "default",
"multi": 1, "multi": 1,
"names": "", "names": "",

View File

@@ -202,8 +202,7 @@ def connect_simple_door(world, exit_name, region_name, player):
d.dest = region d.dest = region
def connect_door_only(world, exit_name, region_name, player): def connect_door_only(world, exit_name, region, player):
region = world.get_region(region_name, player)
d = world.check_for_door(exit_name, player) d = world.check_for_door(exit_name, player)
if d is not None: if d is not None:
d.dest = region d.dest = region
@@ -1357,8 +1356,8 @@ def add_inaccessible_doors(world, player):
# todo: ignore standard mode hyrule castle ledge? # todo: ignore standard mode hyrule castle ledge?
for inaccessible_region in world.inaccessible_regions[player]: for inaccessible_region in world.inaccessible_regions[player]:
region = world.get_region(inaccessible_region, player) region = world.get_region(inaccessible_region, player)
for exit in region.exits: for ext in region.exits:
create_door(world, player, exit.name, region.name) create_door(world, player, ext.name, region.name)
def create_door(world, player, entName, region_name): def create_door(world, player, entName, region_name):
@@ -1464,6 +1463,7 @@ def check_for_pinball_fix(state, bad_region, world, player):
@unique @unique
class DROptions(Flag): class DROptions(Flag):
NoOptions = 0x00
Eternal_Mini_Bosses = 0x01 # If on, GT minibosses marked as defeated when they try to spawn a heart Eternal_Mini_Bosses = 0x01 # If on, GT minibosses marked as defeated when they try to spawn a heart
Town_Portal = 0x02 # If on, Players will start with mirror scroll Town_Portal = 0x02 # If on, Players will start with mirror scroll
Open_Desert_Wall = 0x80 # If on, pre opens the desert wall, no fire required Open_Desert_Wall = 0x80 # If on, pre opens the desert wall, no fire required

View File

@@ -177,6 +177,7 @@ def get_custom_array_key(item):
key = label_switcher.get(key) key = label_switcher.get(key)
return key return key
def generate_itempool(world, player): def generate_itempool(world, player):
if (world.difficulty[player] not in ['normal', 'hard', 'expert'] or world.goal[player] not in ['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals'] if (world.difficulty[player] not in ['normal', 'hard', 'expert'] or world.goal[player] not in ['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals']
or world.mode[player] not in ['open', 'standard', 'inverted'] or world.timer not in ['none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown'] or world.progressive not in ['on', 'off', 'random']): or world.mode[player] not in ['open', 'standard', 'inverted'] or world.timer not in ['none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown'] or world.progressive not in ['on', 'off', 'random']):
@@ -194,7 +195,7 @@ def generate_itempool(world, player):
region = world.get_region('Light World',player) region = world.get_region('Light World',player)
loc = Location(player, "Murahdahla", parent=region) loc = Location(player, "Murahdahla", parent=region)
loc.access_rule = lambda state: state.item_count(get_custom_array_key('Triforce Piece'), player) + state.item_count(get_custom_array_key('Power Star'), player) > state.world.treasure_hunt_count[player] loc.access_rule = lambda state: state.item_count('Triforce Piece', player) + state.item_count('Power Star', player) > state.world.treasure_hunt_count[player]
region.locations.append(loc) region.locations.append(loc)
world.dynamic_locations.append(loc) world.dynamic_locations.append(loc)
@@ -253,7 +254,6 @@ def generate_itempool(world, player):
world.get_location('Zelda Drop Off', player).event = True world.get_location('Zelda Drop Off', player).event = True
world.get_location('Zelda Drop Off', player).locked = True world.get_location('Zelda Drop Off', player).locked = True
# set up item pool # set up item pool
if world.custom: if world.custom:
(pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = make_custom_item_pool(world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.customitemarray) (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = make_custom_item_pool(world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.customitemarray)
@@ -265,10 +265,10 @@ def generate_itempool(world, player):
amt = world.pool_adjustment[player] amt = world.pool_adjustment[player]
if amt < 0: if amt < 0:
for i in range(0, amt): for i in range(0, amt):
pool.remove(get_custom_array_key('Rupees (20)')) pool.remove('Rupees (20)')
elif amt > 0: elif amt > 0:
for i in range(0, amt): for i in range(0, amt):
pool.append(get_custom_array_key('Rupees (20)')) pool.append('Rupees (20)')
for item in precollected_items: for item in precollected_items:
world.push_precollected(ItemFactory(item, player)) world.push_precollected(ItemFactory(item, player))
@@ -407,6 +407,7 @@ def set_up_take_anys(world, player):
world.initialize_regions() world.initialize_regions()
def create_dynamic_shop_locations(world, player): def create_dynamic_shop_locations(world, player):
for shop in world.shops: for shop in world.shops:
if shop.region.player == player: if shop.region.player == player:

View File

@@ -705,7 +705,7 @@ def unique_doors(doors):
def count_unique_sm_doors(doors): def count_unique_sm_doors(doors):
unique_d_set = set() unique_d_set = set()
for d in doors: for d in doors:
if d not in unique_d_set and d.dest not in unique_d_set and not d.bigKey: if d not in unique_d_set and (d.dest not in unique_d_set or d.type == DoorType.SpiralStairs) and not d.bigKey:
unique_d_set.add(d) unique_d_set.add(d)
return len(unique_d_set) return len(unique_d_set)
@@ -718,6 +718,7 @@ def count_unique_small_doors(key_counter, proposal):
if door in proposal and door not in counted: if door in proposal and door not in counted:
cnt += 1 cnt += 1
counted.add(door) counted.add(door)
if door.type != DoorType.SpiralStairs:
counted.add(door.dest) counted.add(door.dest)
return cnt return cnt
@@ -1069,15 +1070,6 @@ def invalid_self_locking_key(state, prev_state, prev_avail, world, player):
return prev_avail - 1 == 0 return prev_avail - 1 == 0
# does not allow dest doors
def count_unique_sm_doors(doors):
unique_d_set = set()
for d in doors:
if d not in unique_d_set and d.dest not in unique_d_set and not d.bigKey:
unique_d_set.add(d)
return len(unique_d_set)
def enough_small_locations(state, avail_small_loc): def enough_small_locations(state, avail_small_loc):
unique_d_set = set() unique_d_set = set()
for exp_door in state.small_doors: for exp_door in state.small_doors:

View File

@@ -24,7 +24,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.18dev' __version__ = '0.0.18.3d'
def main(args, seed=None): def main(args, seed=None):

View File

@@ -148,6 +148,7 @@ def roll_settings(weights):
ret.shuffle = entrance_shuffle if entrance_shuffle != 'none' else 'vanilla' ret.shuffle = entrance_shuffle if entrance_shuffle != 'none' else 'vanilla'
door_shuffle = get_choice('door_shuffle') door_shuffle = get_choice('door_shuffle')
ret.door_shuffle = door_shuffle if door_shuffle != 'none' else 'vanilla' ret.door_shuffle = door_shuffle if door_shuffle != 'none' else 'vanilla'
ret.experimental = get_choice('experimental') == 'on'
goal = get_choice('goals') goal = get_choice('goals')
ret.goal = {'ganon': 'ganon', ret.goal = {'ganon': 'ganon',
@@ -156,7 +157,7 @@ def roll_settings(weights):
'pedestal': 'pedestal', 'pedestal': 'pedestal',
'triforce-hunt': 'triforcehunt' 'triforce-hunt': 'triforcehunt'
}[goal] }[goal]
ret.openpyramid = goal == 'fast_ganon' ret.openpyramid = goal == 'fast_ganon' if ret.shuffle in ['vanilla', 'dungeonsfull', 'dungeonssimple'] else False
ret.crystals_gt = get_choice('tower_open') ret.crystals_gt = get_choice('tower_open')

View File

@@ -36,10 +36,6 @@ Doors are shuffled between dungeons as well.
Doors are not shuffled. Doors are not shuffled.
### Experimental
Used for development testing. This will be removed in a future version. Use at your own risk. Might play like a plando.
## Map/Compass/Small Key/Big Key shuffle (aka Keysanity) ## Map/Compass/Small Key/Big Key shuffle (aka Keysanity)
These settings allow dungeon specific items to be distributed anywhere in the world and not just in their native dungeon. These settings allow dungeon specific items to be distributed anywhere in the world and not just in their native dungeon.

6
Rom.py
View File

@@ -591,7 +591,7 @@ 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 not world.experimental[player] else DROptions.Town_Portal dr_flags = DROptions.Eternal_Mini_Bosses if world.doorShuffle[player] == 'vanilla' or not world.experimental[player] else DROptions.Town_Portal
if world.doorShuffle[player] == 'crossed': if world.doorShuffle[player] == 'crossed':
rom.write_byte(0x139004, 2) rom.write_byte(0x139004, 2)
rom.write_byte(0x151f1, 2) rom.write_byte(0x151f1, 2)
@@ -899,7 +899,7 @@ def patch_rom(world, rom, player, team, enemized):
ERtimeincrease = 20 ERtimeincrease = 20
if world.keyshuffle[player] or world.bigkeyshuffle[player] or world.mapshuffle[player]: if world.keyshuffle[player] or world.bigkeyshuffle[player] or world.mapshuffle[player]:
ERtimeincrease = ERtimeincrease + 15 ERtimeincrease = ERtimeincrease + 15
if world.clock_mode == 'off': if world.clock_mode == 'none':
rom.write_bytes(0x180190, [0x00, 0x00, 0x00]) # turn off clock mode rom.write_bytes(0x180190, [0x00, 0x00, 0x00]) # turn off clock mode
write_int32(rom, 0x180200, 0) # red clock adjustment time (in frames, sint32) write_int32(rom, 0x180200, 0) # red clock adjustment time (in frames, sint32)
write_int32(rom, 0x180204, 0) # blue clock adjustment time (in frames, sint32) write_int32(rom, 0x180204, 0) # blue clock adjustment time (in frames, sint32)
@@ -1157,7 +1157,7 @@ def patch_rom(world, rom, player, team, enemized):
rom.write_byte(0x18003B, 0x01 if world.mapshuffle[player] else 0x00) # maps showing crystals on overworld rom.write_byte(0x18003B, 0x01 if world.mapshuffle[player] else 0x00) # maps showing crystals on overworld
# compasses showing dungeon count # compasses showing dungeon count
if world.clock_mode != 'off' or world.dungeon_counters[player] == 'off': if world.clock_mode != 'none' or world.dungeon_counters[player] == 'off':
rom.write_byte(0x18003C, 0x00) # Currently must be off if timer is on, because they use same HUD location rom.write_byte(0x18003C, 0x00) # Currently must be off if timer is on, because they use same HUD location
elif world.dungeon_counters[player] == 'on': elif world.dungeon_counters[player] == 'on':
rom.write_byte(0x18003C, 0x02) # always on rom.write_byte(0x18003C, 0x02) # always on

View File

@@ -1,10 +1,11 @@
from tkinter import ttk, StringVar, Entry, Frame, Label, N, E, W, LEFT, RIGHT, X, VERTICAL, Y from tkinter import ttk, Frame, N, LEFT, VERTICAL, Y
import gui.widgets as widgets import gui.widgets as widgets
import json import json
import os import os
import classes.constants as CONST import classes.constants as CONST
def custom_page(top, parent): def custom_page(top, parent):
# Custom Item Pool # Custom Item Pool
self = ttk.Frame(parent) self = ttk.Frame(parent)

View File

@@ -37,9 +37,10 @@
"selectbox": { "selectbox": {
"side": "right" "side": "right"
}, },
"default": "Off" "default": "Auto"
}, },
"options": { "options": {
"Auto": "default",
"Off": "off", "Off": "off",
"On": "on", "On": "on",
"On Compass Pickup": "pickup" "On Compass Pickup": "pickup"