Skip to content

Commit

Permalink
SettingsList Revamp
Browse files Browse the repository at this point in the history
Remake SettingInfos as a class with descriptors instead of a simple dictionary.
  • Loading branch information
Cuphat committed May 19, 2023
1 parent f07e6ca commit 044eb12
Show file tree
Hide file tree
Showing 29 changed files with 3,294 additions and 3,304 deletions.
37 changes: 17 additions & 20 deletions Cosmetics.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import Sounds as sfx
import IconManip as icon
from JSONDump import dump_obj, CollapseList, CollapseDict, AlignedDict, SortedDict
from SettingsList import setting_infos
from Plandomizer import InvalidFileException
import json
from itertools import chain
Expand Down Expand Up @@ -90,8 +89,6 @@ def patch_tunic_icon(rom, tunic, color, rainbow=False):


def patch_tunic_colors(rom, settings, log, symbols):
# patch tunic colors

# Need to check for the existence of the CFG_TUNIC_COLORS symbol.
# This was added with rainbow tunic but custom tunic colors should still support older patch versions.
tunic_address = symbols.get('CFG_TUNIC_COLORS', 0x00B6DA38) # Use new tunic color ROM address. Fall back to vanilla tunic color ROM address.
Expand All @@ -102,10 +99,10 @@ def patch_tunic_colors(rom, settings, log, symbols):
]

tunic_color_list = get_tunic_colors()
rainbow_error = None

for tunic, tunic_setting, address in tunics:
tunic_option = settings.__dict__[tunic_setting]
rainbow_error = None
tunic_option = settings.settings_dict[tunic_setting]

# Handle Plando
if log.src_dict.get('equipment_colors', {}).get(tunic, {}).get('color', '') and log.src_dict['equipment_colors'][tunic][':option'] != 'Rainbow':
Expand Down Expand Up @@ -184,8 +181,8 @@ def patch_navi_colors(rom, settings, log, symbols):
rainbow_error = None

for navi_action, navi_setting, navi_addresses, rainbow_inner_symbol, rainbow_outer_symbol in navi:
navi_option_inner = settings.__dict__[navi_setting+'_inner']
navi_option_outer = settings.__dict__[navi_setting+'_outer']
navi_option_inner = settings.settings_dict[navi_setting+'_inner']
navi_option_outer = settings.settings_dict[navi_setting+'_outer']
plando_colors = log.src_dict.get('misc_colors', {}).get(navi_action, {}).get('colors', [])

# choose a random choice for the whole group
Expand Down Expand Up @@ -281,8 +278,8 @@ def patch_sword_trails(rom, settings, log, symbols):
rainbow_error = None

for trail_name, trail_setting, trail_addresses, rainbow_inner_symbol, rainbow_outer_symbol in sword_trails:
option_inner = settings.__dict__[trail_setting+'_inner']
option_outer = settings.__dict__[trail_setting+'_outer']
option_inner = settings.settings_dict[trail_setting+'_inner']
option_outer = settings.settings_dict[trail_setting+'_outer']
plando_colors = log.src_dict.get('misc_colors', {}).get(trail_name, {}).get('colors', [])

# handle random choice
Expand Down Expand Up @@ -395,8 +392,8 @@ def patch_boomerang_trails(rom, settings, log, symbols):
def patch_trails(rom, settings, log, trails):
for trail_name, trail_setting, trail_color_list, trail_color_dict, trail_symbols in trails:
color_inner_symbol, color_outer_symbol, rainbow_inner_symbol, rainbow_outer_symbol = trail_symbols
option_inner = settings.__dict__[trail_setting+'_inner']
option_outer = settings.__dict__[trail_setting+'_outer']
option_inner = settings.settings_dict[trail_setting+'_inner']
option_outer = settings.settings_dict[trail_setting+'_outer']
plando_colors = log.src_dict.get('misc_colors', {}).get(trail_name, {}).get('colors', [])

# handle random choice
Expand Down Expand Up @@ -482,7 +479,7 @@ def patch_gauntlet_colors(rom, settings, log, symbols):
gauntlet_color_list = get_gauntlet_colors()

for gauntlet, gauntlet_setting, address, model_addresses in gauntlets:
gauntlet_option = settings.__dict__[gauntlet_setting]
gauntlet_option = settings.settings_dict[gauntlet_setting]

# Handle Plando
if log.src_dict.get('equipment_colors', {}).get(gauntlet, {}).get('color', ''):
Expand Down Expand Up @@ -521,7 +518,7 @@ def patch_shield_frame_colors(rom, settings, log, symbols):
shield_frame_color_list = get_shield_frame_colors()

for shield_frame, shield_frame_setting, addresses, model_addresses in shield_frames:
shield_frame_option = settings.__dict__[shield_frame_setting]
shield_frame_option = settings.settings_dict[shield_frame_setting]

# Handle Plando
if log.src_dict.get('equipment_colors', {}).get(shield_frame, {}).get('color', ''):
Expand Down Expand Up @@ -565,7 +562,7 @@ def patch_heart_colors(rom, settings, log, symbols):
heart_color_list = get_heart_colors()

for heart, heart_setting, symbol, file_select_address, model_addresses in hearts:
heart_option = settings.__dict__[heart_setting]
heart_option = settings.settings_dict[heart_setting]

# Handle Plando
if log.src_dict.get('ui_colors', {}).get(heart, {}).get('color', ''):
Expand Down Expand Up @@ -613,7 +610,7 @@ def patch_magic_colors(rom, settings, log, symbols):
magic_color_list = get_magic_colors()

for magic_color, magic_setting, symbol, model_addresses in magic:
magic_option = settings.__dict__[magic_setting]
magic_option = settings.settings_dict[magic_setting]

# Handle Plando
if log.src_dict.get('ui_colors', {}).get(magic_color, {}).get('color', ''):
Expand Down Expand Up @@ -682,7 +679,7 @@ def patch_button_colors(rom, settings, log, symbols):
]

for button, button_setting, button_colors, patches in buttons:
button_option = settings.__dict__[button_setting]
button_option = settings.settings_dict[button_setting]
color_set = None
colors = {}
log_dict = CollapseDict({':option': button_option, 'colors': {}})
Expand Down Expand Up @@ -761,7 +758,7 @@ def patch_sfx(rom, settings, log, symbols):
sounds_label_keyword = {sound.value.label: sound.value.keyword for sound in sfx.Sounds}

for setting, hook in sfx_config:
selection = settings.__dict__[setting]
selection = settings.settings_dict[setting]

# Handle Plando
if log.src_dict.get('sfx', {}).get(hook.value.name, ''):
Expand Down Expand Up @@ -809,7 +806,7 @@ def patch_instrument(rom, settings, log, symbols):
'flute': 0x06,
#'another_ocarina': 0x07,
}
ocarina_options = [setting.choices for setting in setting_infos if setting.name == 'sfx_ocarina'][0]
ocarina_options = settings.setting_infos['sfx_ocarina'].choices
ocarina_options_inv = {v: k for k, v in ocarina_options.items()}

choice = settings.sfx_ocarina
Expand Down Expand Up @@ -1194,10 +1191,10 @@ def __init__(self, settings):

if self.src_dict.get('settings', {}):
valid_settings = []
for setting in setting_infos:
for setting in self.settings.setting_infos.values():
if setting.name not in self.src_dict['settings'] or not setting.cosmetic:
continue
self.settings.__dict__[setting.name] = self.src_dict['settings'][setting.name]
self.settings.settings_dict[setting.name] = self.src_dict['settings'][setting.name]
valid_settings.append(setting.name)
for setting in list(self.src_dict['settings'].keys()):
if setting not in valid_settings:
Expand Down
4 changes: 2 additions & 2 deletions Gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import shutil
import webbrowser
from Utils import local_path, data_path, compare_version, VersionError
from SettingsToJson import CreateJSON
from SettingsToJson import create_settings_list_json


def gui_main():
Expand All @@ -28,7 +28,7 @@ def gui_main():

web_version = '--web' in sys.argv
if '--skip-settingslist' not in sys.argv:
CreateJSON(data_path('generated/settings_list.json'), web_version)
create_settings_list_json(data_path('generated/settings_list.json'), web_version)

if web_version:
args = ["node", "run.js", "web"]
Expand Down
4 changes: 2 additions & 2 deletions Main.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def resolve_settings(settings):
logger.error('Tricks are set in two places! Using only the tricks from the distribution file.')

for trick in logic_tricks.values():
settings.__dict__[trick['name']] = trick['name'] in settings.allowed_tricks
settings.settings_dict[trick['name']] = trick['name'] in settings.allowed_tricks

# we load the rom before creating the seed so that errors get caught early
outputting_specific_world = settings.create_uncompressed_rom or settings.create_compressed_rom or settings.create_wad_file
Expand Down Expand Up @@ -124,7 +124,7 @@ def build_world_graphs(settings):
logger = logging.getLogger('')
worlds = []
for i in range(0, settings.world_count):
worlds.append(World(i, copy.copy(settings)))
worlds.append(World(i, settings.copy()))

savewarps_to_connect = []
for id, world in enumerate(worlds):
Expand Down
1 change: 0 additions & 1 deletion Patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from ItemPool import song_list, trade_items, child_trade_items
from SceneFlags import get_alt_list_bytes, get_collectible_flag_table, get_collectible_flag_table_bytes
from texture_util import ci4_rgba16patch_to_ci8, rgba16_patch
from SettingsList import setting_infos


def patch_rom(spoiler: Spoiler, world: World, rom: Rom) -> None:
Expand Down
13 changes: 9 additions & 4 deletions Plandomizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1143,7 +1143,13 @@ def __init__(self, settings, src_dict=None):
'_settings': self.src_dict.get('settings', {}),
}

self.settings.__dict__.update(update_dict['_settings'])
# If the plando is using the GUI-based ("legacy") starting items settings, start with a fresh starting_items dict.
if not update_dict['_settings'].get('starting_items', None):
if (update_dict['_settings'].get('starting_equipment', None) or update_dict['_settings'].get('starting_inventory', None)
or update_dict['_settings'].get('starting_songs', None)):
update_dict['_settings']['starting_items'] = {}

self.settings.settings_dict.update(update_dict['_settings'])
if 'settings' in self.src_dict:
validate_settings(self.src_dict['settings'])
self.src_dict['_settings'] = self.src_dict['settings']
Expand Down Expand Up @@ -1221,7 +1227,7 @@ def reset(self):
world.update({k: self.src_dict[k]})

# normalize starting items to use the dictionary format
starting_items = itertools.chain(self.settings.starting_equipment, self.settings.starting_songs)
starting_items = itertools.chain(self.settings.starting_equipment, self.settings.starting_songs, self.settings.starting_inventory)
data = defaultdict(lambda: StarterRecord(0))
if isinstance(self.settings.starting_items, dict) and self.settings.starting_items:
world_names = ['World %d' % (i + 1) for i in range(len(self.world_dists))]
Expand All @@ -1232,8 +1238,6 @@ def reset(self):
else:
data[name] = record if isinstance(record, StarterRecord) else StarterRecord(record)
add_starting_ammo(data)
else:
starting_items = itertools.chain(self.settings.starting_equipment, self.settings.starting_items, self.settings.starting_songs)
for itemsetting in starting_items:
if itemsetting in StartingItems.everything:
item = StartingItems.everything[itemsetting]
Expand All @@ -1250,6 +1254,7 @@ def reset(self):
raise KeyError("invalid starting item: {}".format(itemsetting))
self.settings.starting_equipment = []
self.settings.starting_songs = []
self.settings.starting_inventory = []
# add hearts
if self.settings.starting_hearts > 3 and 'Piece of Heart' not in self.settings.starting_items and 'Heart Container' not in self.settings.starting_items:
num_hearts_to_collect = self.settings.starting_hearts - 3
Expand Down
12 changes: 6 additions & 6 deletions RuleParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ def visit_Name(self, node):
keywords=[])
elif node.id in self.world.__dict__:
return ast.parse('%r' % self.world.__dict__[node.id], mode='eval').body
elif node.id in self.world.settings.__dict__:
elif node.id in self.world.settings.settings_dict:
# Settings are constant
return ast.parse('%r' % self.world.settings.__dict__[node.id], mode='eval').body
return ast.parse('%r' % self.world.settings.settings_dict[node.id], mode='eval').body
elif node.id in State.__dict__:
return self.make_call(node, node.id, [], [])
elif node.id in kwarg_defaults or node.id in special_globals:
Expand Down Expand Up @@ -142,7 +142,7 @@ def visit_Tuple(self, node):

if isinstance(count, ast.Name):
# Must be a settings constant
count = ast.parse('%r' % self.world.settings.__dict__[count.id], mode='eval').body
count = ast.parse('%r' % self.world.settings.settings_dict[count.id], mode='eval').body

if item.id not in ItemInfo.solver_ids:
self.events.add(item.id.replace('_', ' '))
Expand Down Expand Up @@ -192,7 +192,7 @@ def visit_Call(self, node):
ctx=ast.Load()),
attr=child.id,
ctx=ast.Load())
elif child.id in self.world.settings.__dict__:
elif child.id in self.world.settings.settings_dict:
child = ast.Attribute(
value=ast.Attribute(
value=ast.Attribute(
Expand Down Expand Up @@ -247,7 +247,7 @@ def escape_or_string(n):
if (len(node.ops) == 1 and isinstance(node.ops[0], ast.Eq)
and isinstance(node.left, ast.Name) and isinstance(node.comparators[0], ast.Name)
and node.left.id not in self.world.__dict__ and node.comparators[0].id not in self.world.__dict__
and node.left.id not in self.world.settings.__dict__ and node.comparators[0].id not in self.world.settings.__dict__):
and node.left.id not in self.world.settings.settings_dict and node.comparators[0].id not in self.world.settings.settings_dict):
return ast.NameConstant(node.left.id == node.comparators[0].id)

node.left = escape_or_string(node.left)
Expand Down Expand Up @@ -299,7 +299,7 @@ def visit_BoolOp(self, node):
items.add(escape_name(elt.s))
elif (isinstance(elt, ast.Name) and elt.id not in rule_aliases
and elt.id not in self.world.__dict__
and elt.id not in self.world.settings.__dict__
and elt.id not in self.world.settings.settings_dict
and elt.id not in dir(self)
and elt.id not in State.__dict__):
items.add(elt.id)
Expand Down
Loading

0 comments on commit 044eb12

Please sign in to comment.