Merge branch 'DoorDevUnstable' into DoorDevVolatile

# Conflicts:
#	Main.py
#	MultiClient.py
#	Rom.py
#	data/base2current.bps
#	resources/app/gui/lang/en.json
#	resources/app/gui/randomize/item/widgets.json
#	source/gui/bottom.py
#	source/gui/widgets.py
This commit is contained in:
aerinon
2023-08-04 11:33:31 -06:00
31 changed files with 289 additions and 155 deletions

View File

@@ -2,6 +2,7 @@ import os
import urllib.request
import urllib.parse
import yaml
from typing import Any
from yaml.representer import Representer
from collections import defaultdict
from pathlib import Path
@@ -46,8 +47,8 @@ class CustomSettings(object):
return meta['players']
def adjust_args(self, args):
def get_setting(value, default):
if value:
def get_setting(value: Any, default):
if value or value == 0:
if isinstance(value, dict):
return random.choices(list(value.keys()), list(value.values()), k=1)[0]
else:
@@ -117,6 +118,7 @@ class CustomSettings(object):
args.crystals_gt[p] = get_setting(settings['crystals_gt'], args.crystals_gt[p])
args.crystals_ganon[p] = get_setting(settings['crystals_ganon'], args.crystals_ganon[p])
args.experimental[p] = get_setting(settings['experimental'], args.experimental[p])
args.collection_rate[p] = get_setting(settings['collection_rate'], args.collection_rate[p])
args.openpyramid[p] = get_setting(settings['openpyramid'], args.openpyramid[p])
args.bigkeyshuffle[p] = get_setting(settings['bigkeyshuffle'], args.bigkeyshuffle[p])
args.keyshuffle[p] = get_setting(settings['keyshuffle'], args.keyshuffle[p])
@@ -144,6 +146,12 @@ class CustomSettings(object):
args.pseudoboots[p] = get_setting(settings['pseudoboots'], args.pseudoboots[p])
args.triforce_goal[p] = get_setting(settings['triforce_goal'], args.triforce_goal[p])
args.triforce_pool[p] = get_setting(settings['triforce_pool'], args.triforce_pool[p])
args.triforce_goal_min[p] = get_setting(settings['triforce_goal_min'], args.triforce_goal_min[p])
args.triforce_goal_max[p] = get_setting(settings['triforce_goal_max'], args.triforce_goal_max[p])
args.triforce_pool_min[p] = get_setting(settings['triforce_pool_min'], args.triforce_pool_min[p])
args.triforce_pool_max[p] = get_setting(settings['triforce_pool_max'], args.triforce_pool_max[p])
args.triforce_min_difference[p] = get_setting(settings['triforce_min_difference'], args.triforce_min_difference[p])
args.triforce_max_difference[p] = get_setting(settings['triforce_max_difference'], args.triforce_max_difference[p])
args.beemizer[p] = get_setting(settings['beemizer'], args.beemizer[p])
# mystery usage
@@ -251,6 +259,7 @@ class CustomSettings(object):
settings_dict[p]['crystals_gt'] = world.crystals_gt_orig[p]
settings_dict[p]['crystals_ganon'] = world.crystals_ganon_orig[p]
settings_dict[p]['experimental'] = world.experimental[p]
settings_dict[p]['collection_rate'] = world.collection_rate[p]
settings_dict[p]['openpyramid'] = world.open_pyramid[p]
settings_dict[p]['bigkeyshuffle'] = world.bigkeyshuffle[p]
settings_dict[p]['keyshuffle'] = world.keyshuffle[p]

View File

@@ -66,6 +66,7 @@ SETTINGSTOPROCESS = {
"crystals_ganon": "crystals_ganon",
"weapons": "swords",
"retro": "retro",
"sortingalgo": "algorithm",
"accessibility": "accessibility",
"restrict_boss_items": "restrict_boss_items",

View File

@@ -214,7 +214,8 @@ def create_guiargs(parent):
arg = options[mainpage][subpage][widget] if subpage != "" else options[mainpage][widget]
page = parent.pages[mainpage].pages[subpage] if subpage != "" else parent.pages[mainpage]
pagewidgets = page.content.customWidgets if mainpage == "custom" else page.content.startingWidgets if mainpage == "startinventory" else page.widgets
setattr(guiargs, arg, pagewidgets[widget].storageVar.get())
if hasattr(pagewidgets[widget], 'storageVar'):
setattr(guiargs, arg, pagewidgets[widget].storageVar.get())
# Get Multiworld Worlds count
guiargs.multi = int(parent.pages["bottom"].pages["content"].widgets["worlds"].storageVar.get())
@@ -282,17 +283,4 @@ def create_guiargs(parent):
guiargs = update_deprecated_args(guiargs)
# Key drop shuffle stuff
if guiargs.keydropshuffle:
guiargs.dropshuffle = 'keys' if guiargs.dropshuffle == 'none' else guiargs.dropshuffle
guiargs.pottery = 'keys' if guiargs.pottery == 'none' else guiargs.pottery
if (hasattr(guiargs, 'retro') and guiargs.retro) or guiargs.mode == 'retro':
if guiargs.bow_mode == 'progressive':
guiargs.bow_mode = 'retro'
elif guiargs.bow_mode == 'silvers':
guiargs.bow_mode = 'retro_silvers'
guiargs.take_any = 'random' if guiargs.take_any == 'none' else guiargs.take_any
guiargs.keyshuffle = 'universal'
return guiargs

View File

@@ -57,7 +57,10 @@ def loadcliargs(gui, args, settings=None):
pagewidgets[widget].selectbox.options = theseOptions
elif thisType == "spinbox":
pagewidgets[widget].label.configure(text=label)
pagewidgets[widget].storageVar.set(args[arg])
elif thisType == 'button':
pagewidgets[widget].button.configure(text=label)
if hasattr(pagewidgets[widget], 'storageVar'):
pagewidgets[widget].storageVar.set(args[arg])
# If we're on the Game Options page and it's not about Hints
if subpage == "gameoptions" and widget not in ["hints", "collection_rate"]:
# Check if we've got settings

View File

@@ -43,7 +43,10 @@ def item_page(parent):
self.frames["leftPoolHeader"].pack(side=TOP, anchor=W)
self.frames["leftPoolFrame"] = Frame(self.frames["leftPoolContainer"])
self.frames["leftPoolFrame"].pack(side=LEFT, fill=Y)
self.frames["leftPoolFrame"].pack(side=TOP, fill=Y)
self.frames["leftPoolFrame2"] = Frame(self.frames["leftPoolContainer"])
self.frames["leftPoolFrame2"].pack(side=LEFT, fill=Y)
self.frames["rightPoolFrame"] = Frame(self.frames["poolFrame"])
self.frames["rightPoolFrame"].pack(side=RIGHT)
@@ -62,14 +65,16 @@ def item_page(parent):
for key in dictWidgets:
self.widgets[key] = dictWidgets[key]
packAttrs = {"anchor":E}
if self.widgets[key].type == "checkbox" or framename == "leftPoolFrame":
if key == "retro":
packAttrs["side"] = RIGHT
if self.widgets[key].type == "checkbox" or framename.startswith("leftPoolFrame"):
packAttrs["anchor"] = W
if framename == "checkboxes":
packAttrs["side"] = LEFT
packAttrs["padx"] = (10,0)
packAttrs["padx"] = (10, 0)
elif framename == "leftPoolHeader":
packAttrs["side"] = LEFT
packAttrs["padx"] = (0,20)
packAttrs["padx"] = (0, 20)
packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key])
self.widgets[key].pack(packAttrs)

View File

@@ -1,4 +1,6 @@
from tkinter import messagebox, Checkbutton, Entry, Frame, IntVar, Label, OptionMenu, Spinbox, StringVar, LEFT, RIGHT, X
from tkinter import Button
from source.classes.Empty import Empty
# Override Spinbox to include mousewheel support for changing value
@@ -172,6 +174,22 @@ def make_textbox(self, parent, label, storageVar, manager, managerAttrs):
widget.textbox.pack(managerAttrs["textbox"] if managerAttrs is not None and "textbox" in managerAttrs else None)
return widget
def make_button(self, parent, label, manager, managerAttrs, config):
self = Frame(parent)
if config and "command" in config:
self.command = config["command"]
else:
self.command = lambda: None
self.button = Button(parent, text=label, command=lambda: widget_command(self, self.command))
if managerAttrs is not None:
self.button.pack(managerAttrs)
else:
self.button.pack(anchor='w')
return self
# Make a generic widget
def make_widget(self, type, parent, label, storageVar=None, manager=None, managerAttrs=dict(),
options=None, config=None):
@@ -201,6 +219,8 @@ def make_widget(self, type, parent, label, storageVar=None, manager=None, manage
if thisStorageVar is None:
thisStorageVar = StringVar()
widget = make_textbox(self, parent, label, thisStorageVar, manager, managerAttrs)
elif type == 'button':
widget = make_button(self, parent, label, manager, managerAttrs, config)
widget.type = type
return widget
@@ -243,47 +263,36 @@ def add_padding_from_config(packAttrs, defn):
def widget_command(widget, command=""):
root = widget.winfo_toplevel()
text_output = ""
if command == "worldstate":
if widget.storageVar.get() == 'retro':
temp_widget = root.pages["randomizer"].pages["dungeon"].widgets["smallkeyshuffle"]
text_output += f'\n {temp_widget.label.cget("text")}'
temp_widget.storageVar.set('universal')
if command == "retro":
temp_widget = root.pages["randomizer"].pages["dungeon"].widgets["smallkeyshuffle"]
text_output += f'\n {temp_widget.label.cget("text")}'
temp_widget.storageVar.set('universal')
temp_widget = root.pages["randomizer"].pages["item"].widgets["bow_mode"]
text_output += f'\n {temp_widget.label.cget("text")}'
if temp_widget.storageVar.get() == 'progressive':
temp_widget.storageVar.set('retro')
elif temp_widget.storageVar.get() == 'silvers':
temp_widget.storageVar.set('retro_silvers')
temp_widget = root.pages["randomizer"].pages["item"].widgets["bow_mode"]
text_output += f'\n {temp_widget.label.cget("text")}'
if temp_widget.storageVar.get() == 'progressive':
temp_widget.storageVar.set('retro')
elif temp_widget.storageVar.get() == 'silvers':
temp_widget.storageVar.set('retro_silvers')
temp_widget = root.pages["randomizer"].pages["item"].widgets["take_any"]
text_output += f'\n {temp_widget.label.cget("text")}'
if temp_widget.storageVar.get() == 'none':
temp_widget.storageVar.set('random')
temp_widget = root.pages["randomizer"].pages["item"].widgets["take_any"]
text_output += f'\n {temp_widget.label.cget("text")}'
if temp_widget.storageVar.get() == 'none':
temp_widget.storageVar.set('random')
widget.storageVar.set('open')
messagebox.showinfo('', f'The following settings were changed:{text_output}')
messagebox.showinfo('', f'The following settings were changed:{text_output}')
elif command == "keydropshuffle":
if widget.storageVar.get() > 0:
temp_widget = root.pages["randomizer"].pages["item"].widgets["pottery"]
if temp_widget.storageVar.get() == 'none':
text_output += f'\n {temp_widget.label.cget("text")}'
temp_widget.storageVar.set('keys')
temp_widget = root.pages["randomizer"].pages["item"].widgets["pottery"]
text_output += f'\n {temp_widget.label.cget("text")}'
if temp_widget.storageVar.get() == 'none':
temp_widget.storageVar.set('keys')
temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"]
text_output += f'\n {temp_widget.label.cget("text")}'
if temp_widget.storageVar.get() == 'none':
temp_widget.storageVar.set('keys')
if text_output:
messagebox.showinfo('', f'The following settings were changed:{text_output}')
temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"]
if temp_widget.storageVar.get() == 'none':
temp_widget.storageVar.set('keys')
text_output += f'\n {temp_widget.label.cget("text")}'
if text_output:
messagebox.showinfo('', f'The following settings were changed:{text_output}')
else:
temp_widget = root.pages["randomizer"].pages["item"].widgets["pottery"]
if temp_widget.storageVar.get() == 'keys':
text_output += f'\n {temp_widget.label.cget("text")}'
temp_widget.storageVar.set('none')
temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"]
if temp_widget.storageVar.get() == 'keys':
temp_widget.storageVar.set('none')
text_output += f'\n {temp_widget.label.cget("text")}'
if text_output:
messagebox.showinfo('', f'The following settings were changed:{text_output}')

View File

@@ -151,9 +151,6 @@ def create_item_pool_config(world):
config.item_pool[player] = determine_major_items(world, player)
config.location_groups[0].locations = set(groups.locations)
config.reserved_locations[player].update(groups.locations)
backup = (mode_grouping['Heart Pieces'] + mode_grouping['Dungeon Trash'] + mode_grouping['Shops']
+ mode_grouping['Overworld Trash'] + mode_grouping['GT Trash'] + mode_grouping['RetroShops'])
config.location_groups[1].locations = set(backup)
elif world.algorithm == 'dungeon_only':
config.location_groups = [
LocationGroup('Dungeons'),
@@ -171,9 +168,6 @@ def create_item_pool_config(world):
for player in range(1, world.players + 1):
config.item_pool[player] = determine_major_items(world, player)
config.location_groups[0].locations = set(dungeon_set)
backup = (mode_grouping['Heart Pieces'] + mode_grouping['Overworld Major']
+ mode_grouping['Overworld Trash'] + mode_grouping['Shops'] + mode_grouping['RetroShops'])
config.location_groups[1].locations = set(backup)
def district_item_pool_config(world):
@@ -419,11 +413,7 @@ def filter_locations(item_to_place, locations, world, vanilla_skip=False, potion
if item_to_place.name in config.item_pool[item_to_place.player]:
restricted = config.location_groups[0].locations
filtered = [l for l in locations if l.name in restricted]
if len(filtered) == 0:
restricted = config.location_groups[1].locations
filtered = [l for l in locations if l.name in restricted]
# bias toward certain location in overflow? (thinking about this for major_bias)
return filtered if len(filtered) > 0 else locations
return filtered
if world.algorithm == 'district':
config = world.item_pool_config
if ((isinstance(item_to_place,str) and item_to_place == 'Placeholder')

View File

@@ -56,6 +56,8 @@ def link_entrances_new(world, player):
one_way_map.update(drop_map)
one_way_map.update(single_entrance_map)
if avail_pool.inverted:
default_map['Ganons Tower'] = 'Agahnims Tower Exit'
default_map['Agahnims Tower'] = 'Ganons Tower Exit'
default_map['Old Man Cave (West)'] = 'Bumper Cave Exit (Bottom)'
default_map['Death Mountain Return Cave (West)'] = 'Bumper Cave Exit (Top)'
default_map['Bumper Cave (Bottom)'] = 'Old Man Cave Exit (West)'
@@ -64,8 +66,6 @@ def link_entrances_new(world, player):
default_map['Old Man Cave (East)'] = 'Death Mountain Return Cave Exit (West)'
one_way_map['Bumper Cave (Top)'] = 'Dark Death Mountain Healer Fairy'
del default_map['Bumper Cave (Top)']
del one_way_map['Big Bomb Shop']
one_way_map['Inverted Big Bomb Shop'] = 'Inverted Big Bomb Shop'
avail_pool.default_map = default_map
avail_pool.one_way_map = one_way_map
@@ -1964,6 +1964,8 @@ mandatory_connections = [('Links House S&Q', 'Links House'),
('Grassy Lawn Pegs (Top)', 'West Dark World'),
('Grassy Lawn Pegs (Bottom)', 'Dark Grassy Lawn'),
('West Dark World Gap', 'West Dark World'),
('Dark Graveyard Bush (South)', 'Dark Graveyard North'),
('Dark Graveyard Bush (North)', 'West Dark World'),
('Broken Bridge Pass (Top)', 'East Dark World'),
('Broken Bridge Pass (Bottom)', 'Northeast Dark World'),
('Peg Area Rocks (Left)', 'Hammer Peg Area'),
@@ -2746,7 +2748,7 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d),
'Dark Lake Hylia Ledge Hint': (0xec0, 0xc00),
'Hype Cave': (0x940, 0xc80),
'Bonk Fairy (Dark)': (0x740, 0xa80),
'Brewery': (0x170, 0x980), 'C-Shaped House': (0x310, 0x7a0), 'Chest Game': (0x800, 0x7a0),
'Brewery': (0x170, 0x980), 'C-Shaped House': (0x310, 0x7a0), 'Chest Game': (0x080, 0x7a0),
'Hammer Peg Cave': (0x4c0, 0x940),
'Red Shield Shop': (0x500, 0x680),
'Dark Sanctuary Hint': (0x720, 0x4a0),

View File

@@ -126,15 +126,14 @@ def roll_settings(weights):
ret.crystals_ganon = get_choice('ganon_open')
from ItemList import set_default_triforce
default_tf_goal, default_tf_pool = set_default_triforce(ret.goal, 0, 0)
goal_min = get_choice_default('triforce_goal_min', default=default_tf_goal)
goal_max = get_choice_default('triforce_goal_max', default=default_tf_goal)
pool_min = get_choice_default('triforce_pool_min', default=default_tf_pool)
pool_max = get_choice_default('triforce_pool_max', default=default_tf_pool)
ret.triforce_goal = random.randint(int(goal_min), int(goal_max))
min_diff = get_choice_default('triforce_min_difference', default=default_tf_pool-default_tf_goal)
ret.triforce_pool = random.randint(max(int(pool_min), ret.triforce_goal + int(min_diff)), int(pool_max))
ret.triforce_pool = get_choice_default('triforce_pool', default=0)
ret.triforce_goal = get_choice_default('triforce_goal', default=0)
ret.triforce_pool_min = get_choice_default('triforce_pool_min', default=0)
ret.triforce_pool_max = get_choice_default('triforce_pool_max', default=0)
ret.triforce_goal_min = get_choice_default('triforce_goal_min', default=0)
ret.triforce_goal_max = get_choice_default('triforce_goal_max', default=0)
ret.triforce_min_difference = get_choice_default('triforce_min_difference', default=0)
ret.triforce_max_difference = get_choice_default('triforce_max_difference', default=10000)
ret.mode = get_choice('world_state')
if ret.mode == 'retro':