Fix var loading again

Update Deprecated Args
Parse CLI
Parse Settings
Fix defaults
Fix priority
Add Enemizer error
Fix Custom Item Array again
Make output more verbose
Fix double-negative options
This commit is contained in:
Mike A. Trethewey
2020-03-22 02:53:40 -07:00
parent f28b1d15c6
commit 8513b7f270
15 changed files with 185 additions and 85 deletions

69
CLI.py
View File

@@ -11,27 +11,22 @@ import sys
import source.classes.constants as CONST import source.classes.constants as CONST
from source.classes.BabelFish import BabelFish from source.classes.BabelFish import BabelFish
from Utils import update_deprecated_args
class ArgumentDefaultsHelpFormatter(argparse.RawTextHelpFormatter): class ArgumentDefaultsHelpFormatter(argparse.RawTextHelpFormatter):
def _get_help_string(self, action): def _get_help_string(self, action):
return textwrap.dedent(action.help) return textwrap.dedent(action.help)
def parse_arguments(argv, no_defaults=False): def parse_cli(argv, no_defaults=False):
def defval(value): def defval(value):
return value if not no_defaults else None return value if not no_defaults else None
# get settings # get settings
settings = get_settings() settings = parse_settings()
lang = "en" lang = "en"
if argv is not None:
priority = get_args_priority(None, None, argv)
if "load" in priority:
priority = priority["load"]
if "lang" in priority:
lang = priority["lang"]
fish = BabelFish(lang=lang) fish = BabelFish(lang=lang)
# we need to know how many players we have first # we need to know how many players we have first
@@ -57,13 +52,18 @@ def parse_arguments(argv, no_defaults=False):
argatts["const"] = argdata["choices"][0] argatts["const"] = argdata["choices"][0]
argatts["default"] = argdata["choices"][0] argatts["default"] = argdata["choices"][0]
argatts["nargs"] = "?" argatts["nargs"] = "?"
elif arg in settings: if arg in settings:
argatts["default"] = defval(settings[arg] != 0) if "type" in argdata and argdata["type"] == "bool" else defval(settings[arg]) default = settings[arg]
if "type" in argdata and argdata["type"] == "bool":
default = settings[arg] != 0
argatts["default"] = defval(default)
arghelp = fish.translate("cli","help",arg) arghelp = fish.translate("cli","help",arg)
if "help" in argdata and argdata["help"] == "suppress": if "help" in argdata and argdata["help"] == "suppress":
argatts["help"] = argparse.SUPPRESS argatts["help"] = argparse.SUPPRESS
elif not isinstance(arghelp,str): elif not isinstance(arghelp,str):
argatts["help"] = '\n'.join(arghelp).replace("\\'","'") argatts["help"] = '\n'.join(arghelp).replace("\\'","'")
else:
argatts["help"] = arghelp + " " + argatts["help"]
parser.add_argument(argname,**argatts) parser.add_argument(argname,**argatts)
parser.add_argument('--seed', default=defval(int(settings["seed"]) if settings["seed"] != "" and settings["seed"] is not None else None), help="\n".join(fish.translate("cli","help","seed")), type=int) parser.add_argument('--seed', default=defval(int(settings["seed"]) if settings["seed"] != "" and settings["seed"] is not None else None), help="\n".join(fish.translate("cli","help","seed")), type=int)
@@ -87,7 +87,7 @@ def parse_arguments(argv, no_defaults=False):
if multiargs.multi: if multiargs.multi:
defaults = copy.deepcopy(ret) defaults = copy.deepcopy(ret)
for player in range(1, multiargs.multi + 1): for player in range(1, multiargs.multi + 1):
playerargs = parse_arguments(shlex.split(getattr(ret,f"p{player}")), True) playerargs = parse_cli(shlex.split(getattr(ret,f"p{player}")), True)
for name in ['logic', 'mode', 'swords', 'goal', 'difficulty', 'item_functionality', for name in ['logic', 'mode', 'swords', 'goal', 'difficulty', 'item_functionality',
'shuffle', 'door_shuffle', 'crystals_ganon', 'crystals_gt', 'openpyramid', 'shuffle', 'door_shuffle', 'crystals_ganon', 'crystals_gt', 'openpyramid',
@@ -105,7 +105,7 @@ def parse_arguments(argv, no_defaults=False):
return ret return ret
def get_settings(): def parse_settings():
# set default settings # set default settings
settings = { settings = {
"lang": "en", "lang": "en",
@@ -151,14 +151,16 @@ def get_settings():
"quickswap": False, "quickswap": False,
"heartcolor": "red", "heartcolor": "red",
"heartbeep": "normal", "heartbeep": "normal",
"sprite": None, "sprite": os.path.join(".","data","sprites","official","001.link.1.zspr"),
"fastmenu": "normal", "fastmenu": "normal",
"ow_palettes": "default", "ow_palettes": "default",
"uw_palettes": "default", "uw_palettes": "default",
"create_spoiler": False, "create_spoiler": False,
"skip_playthrough": False, "skip_playthrough": False,
"calc_playthrough": True,
"suppress_rom": False, "suppress_rom": False,
"create_rom": True,
"usestartinventory": False, "usestartinventory": False,
"custom": False, "custom": False,
"rom": os.path.join(".", "Zelda no Densetsu - Kamigami no Triforce (Japan).sfc"), "rom": os.path.join(".", "Zelda no Densetsu - Kamigami no Triforce (Japan).sfc"),
@@ -267,8 +269,8 @@ def get_settings():
# 3: Canned defaults # 3: Canned defaults
def get_args_priority(settings_args, gui_args, cli_args): def get_args_priority(settings_args, gui_args, cli_args):
args = {} args = {}
args["settings"] = get_settings() if settings_args is None else settings_args args["settings"] = parse_settings() if settings_args is None else settings_args
args["gui"] = {} if gui_args is None else gui_args args["gui"] = gui_args
args["cli"] = cli_args args["cli"] = cli_args
args["load"] = args["settings"] args["load"] = args["settings"]
@@ -279,17 +281,38 @@ def get_args_priority(settings_args, gui_args, cli_args):
if args["cli"] is None: if args["cli"] is None:
args["cli"] = {} args["cli"] = {}
cli = vars(parse_arguments(None)) cli = vars(parse_cli(None))
for k, v in cli.items(): for k, v in cli.items():
if isinstance(v, dict) and 1 in v: if isinstance(v, dict) and 1 in v:
args["cli"][k] = v[1] args["cli"][k] = v[1]
else: else:
args["cli"][k] = v args["cli"][k] = v
load_doesnt_have_key = k not in args["load"] args["cli"] = argparse.Namespace(**args["cli"])
different_val = (k in args["load"] and k in args["cli"]) and (args["load"][k] != args["cli"][k])
cli_has_empty_dict = k in args["cli"] and isinstance(args["cli"][k], dict) and len(args["cli"][k]) == 0 cli = vars(args["cli"])
if load_doesnt_have_key or different_val: for k in vars(args["cli"]):
if not cli_has_empty_dict: load_doesnt_have_key = k not in args["load"]
args["load"][k] = args["cli"][k] cli_val = cli[k]
if isinstance(cli_val,dict) and 1 in cli_val:
cli_val = cli_val[1]
different_val = (k in args["load"] and k in cli) and (str(args["load"][k]) != str(cli_val))
cli_has_empty_dict = k in cli and isinstance(cli_val, dict) and len(cli_val) == 0
if load_doesnt_have_key or different_val:
if not cli_has_empty_dict:
args["load"][k] = cli_val
newArgs = {}
for key in [ "settings", "gui", "cli", "load" ]:
if args[key]:
if isinstance(args[key],dict):
newArgs[key] = argparse.Namespace(**args[key])
else:
newArgs[key] = args[key]
newArgs[key] = update_deprecated_args(newArgs[key])
else:
newArgs[key] = args[key]
args = newArgs
return args return args

View File

@@ -10,14 +10,14 @@ import sys
from source.classes.BabelFish import BabelFish from source.classes.BabelFish import BabelFish
from CLI import parse_arguments, get_args_priority from CLI import parse_cli, get_args_priority
from Main import main from Main import main, EnemizerError
from Rom import get_sprite_from_name from Rom import get_sprite_from_name
from Utils import is_bundled, close_console from Utils import is_bundled, close_console
from Fill import FillError from Fill import FillError
def start(): def start():
args = parse_arguments(None) args = parse_cli(None)
if is_bundled() and len(sys.argv) == 1: if is_bundled() and len(sys.argv) == 1:
# for the bundled builds, if we have no arguments, the user # for the bundled builds, if we have no arguments, the user
@@ -44,10 +44,10 @@ def start():
loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[args.loglevel] loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[args.loglevel]
logging.basicConfig(format='%(message)s', level=loglevel) logging.basicConfig(format='%(message)s', level=loglevel)
settings = get_args_priority(None, None, None) priority = get_args_priority(None, None, args)
lang = "en" lang = "en"
if "load" in settings and "lang" in settings["load"]: if "load" in priority and "lang" in priority["load"]:
lang = settings["load"]["lang"] lang = priority["load"].lang
fish = BabelFish(lang=lang) fish = BabelFish(lang=lang)
if args.gui: if args.gui:
@@ -61,7 +61,7 @@ def start():
try: try:
main(seed=seed, args=args, fish=fish) main(seed=seed, args=args, fish=fish)
logger.info('%s %s', fish.translate("cli","cli","finished.run"), _+1) logger.info('%s %s', fish.translate("cli","cli","finished.run"), _+1)
except (FillError, Exception, RuntimeError) as err: except (FillError, EnemizerError, Exception, RuntimeError) as err:
failures.append((err, seed)) failures.append((err, seed))
logger.warning('%s: %s', fish.translate("cli","cli","generation.failed"), err) logger.warning('%s: %s', fish.translate("cli","cli","generation.failed"), err)
seed = random.randint(0, 999999999) seed = random.randint(0, 999999999)

16
Gui.py
View File

@@ -5,7 +5,7 @@ import sys
from tkinter import Tk, Button, BOTTOM, TOP, StringVar, BooleanVar, X, BOTH, RIGHT, ttk, messagebox from tkinter import Tk, Button, BOTTOM, TOP, StringVar, BooleanVar, X, BOTH, RIGHT, ttk, messagebox
from CLI import get_args_priority from CLI import get_args_priority
from DungeonRandomizer import parse_arguments from DungeonRandomizer import parse_cli
from source.gui.adjust.overview import adjust_page from source.gui.adjust.overview import adjust_page
from source.gui.startinventory.overview import startinventory_page from source.gui.startinventory.overview import startinventory_page
from source.gui.custom.overview import custom_page from source.gui.custom.overview import custom_page
@@ -77,9 +77,13 @@ def guiMain(args=None):
# get args # get args
# getting Settings & CLI (no GUI built yet) # getting Settings & CLI (no GUI built yet)
self.args = get_args_priority(None, None, None) self.args = get_args_priority(None, None, None)
lang = "en"
if "load" in self.args and "lang" in self.args["load"]:
lang = self.args["load"].lang
self.fish = BabelFish(lang=lang)
# get saved settings # get saved settings
self.settings = self.args["settings"] self.settings = vars(self.args["settings"])
# make array for pages # make array for pages
self.pages = {} self.pages = {}
@@ -146,12 +150,6 @@ def guiMain(args=None):
# add randomizer notebook to main window # add randomizer notebook to main window
self.pages["randomizer"].notebook.pack() self.pages["randomizer"].notebook.pack()
settings = get_args_priority(None, None, None)
lang = "en"
if "load" in settings and "lang" in settings["load"]:
lang = settings["load"]["lang"]
self.fish = BabelFish(lang=lang)
# bottom of window: Open Output Directory, Open Documentation (if exists) # bottom of window: Open Output Directory, Open Documentation (if exists)
self.pages["bottom"] = Empty() self.pages["bottom"] = Empty()
self.pages["bottom"].pages = {} self.pages["bottom"].pages = {}
@@ -196,5 +194,5 @@ def guiMain(args=None):
if __name__ == '__main__': if __name__ == '__main__':
args = parse_arguments(None) args = parse_cli(None)
guiMain(args) guiMain(args)

View File

@@ -258,7 +258,7 @@ def generate_itempool(world, player):
# 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)
world.rupoor_cost = min(world.customitemarray["rupoorcost"], 9999) world.rupoor_cost = min(world.customitemarray[player]["rupoorcost"], 9999)
else: else:
(pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.doorShuffle[player]) (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle[player], world.difficulty[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.doorShuffle[player])
@@ -322,9 +322,9 @@ def generate_itempool(world, player):
# logic has some branches where having 4 hearts is one possible requirement (of several alternatives) # logic has some branches where having 4 hearts is one possible requirement (of several alternatives)
# rather than making all hearts/heart pieces progression items (which slows down generation considerably) # rather than making all hearts/heart pieces progression items (which slows down generation considerably)
# We mark one random heart container as an advancement item (or 4 heart pieces in expert mode) # We mark one random heart container as an advancement item (or 4 heart pieces in expert mode)
if world.difficulty[player] in ['normal', 'hard'] and not (world.custom and world.customitemarray["heartcontainer"] == 0): if world.difficulty[player] in ['normal', 'hard'] and not (world.custom and world.customitemarray[player]["heartcontainer"] == 0):
[item for item in items if item.name == 'Boss Heart Container'][0].advancement = True [item for item in items if item.name == 'Boss Heart Container'][0].advancement = True
elif world.difficulty[player] in ['expert'] and not (world.custom and world.customitemarray["heartpiece"] < 4): elif world.difficulty[player] in ['expert'] and not (world.custom and world.customitemarray[player]["heartpiece"] < 4):
adv_heart_pieces = [item for item in items if item.name == 'Piece of Heart'][0:4] adv_heart_pieces = [item for item in items if item.name == 'Piece of Heart'][0:4]
for hp in adv_heart_pieces: for hp in adv_heart_pieces:
hp.advancement = True hp.advancement = True
@@ -601,6 +601,8 @@ def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, r
return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms)
def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, customitemarray): def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, customitemarray):
if isinstance(customitemarray,dict) and 1 in customitemarray:
customitemarray = customitemarray[1]
pool = [] pool = []
placed_items = {} placed_items = {}
precollected_items = [] precollected_items = []
@@ -698,7 +700,7 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s
itemtotal = itemtotal - 28 # Corrects for small keys not being in item pool in Retro Mode itemtotal = itemtotal - 28 # Corrects for small keys not being in item pool in Retro Mode
if itemtotal < total_items_to_place: if itemtotal < total_items_to_place:
nothings = total_items_to_place - itemtotal nothings = total_items_to_place - itemtotal
print("Placing " + str(nothings) + " Nothings") # print("Placing " + str(nothings) + " Nothings")
pool.extend(['Nothing'] * nothings) pool.extend(['Nothing'] * nothings)
return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms) return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms)

26
Main.py
View File

@@ -26,6 +26,8 @@ from Utils import output_path, parse_player_names, print_wiki_doors_by_region, p
__version__ = '0.0.18.6d' __version__ = '0.0.18.6d'
class EnemizerError(RuntimeError):
pass
def main(args, seed=None, fish=None): def main(args, seed=None, fish=None):
if args.outputpath: if args.outputpath:
@@ -180,13 +182,12 @@ def main(args, seed=None, fish=None):
if not world.can_beat_game(): if not world.can_beat_game():
raise RuntimeError(world.fish.translate("cli","cli","cannot.beat.game")) raise RuntimeError(world.fish.translate("cli","cli","cannot.beat.game"))
logger.info(world.fish.translate("cli","cli","patching.rom"))
outfilebase = 'DR_%s' % (args.outputname if args.outputname else world.seed) outfilebase = 'DR_%s' % (args.outputname if args.outputname else world.seed)
rom_names = [] rom_names = []
jsonout = {} jsonout = {}
if not args.suppress_rom: if not args.suppress_rom:
logger.info(world.fish.translate("cli","cli","patching.rom"))
for team in range(world.teams): for team in range(world.teams):
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
sprite_random_on_hit = type(args.sprite[player]) is str and args.sprite[player].lower() == 'randomonhit' sprite_random_on_hit = type(args.sprite[player]) is str and args.sprite[player].lower() == 'randomonhit'
@@ -199,13 +200,17 @@ def main(args, seed=None, fish=None):
patch_rom(world, rom, player, team, use_enemizer) patch_rom(world, rom, player, team, use_enemizer)
if use_enemizer and (args.enemizercli or not args.jsonout): if use_enemizer and (args.enemizercli or not args.jsonout):
if args.rom and not(os.path.isfile(args.rom)):
raise RuntimeError("Could not find valid base rom for enemizing at expected path %s." % args.rom)
if os.path.exists(args.enemizercli): if os.path.exists(args.enemizercli):
patch_enemizer(world, player, rom, args.rom, args.enemizercli, args.shufflepots[player], sprite_random_on_hit) patch_enemizer(world, player, rom, args.rom, args.enemizercli, args.shufflepots[player], sprite_random_on_hit)
if not args.jsonout: if not args.jsonout:
rom = LocalRom.fromJsonRom(rom, args.rom, 0x400000) rom = LocalRom.fromJsonRom(rom, args.rom, 0x400000)
else: else:
logging.warning(world.fish.translate("cli","cli","enemizer.not.found") + ': ' + args.enemizercli) enemizerMsg = world.fish.translate("cli","cli","enemizer.not.found") + ': ' + args.enemizercli + "\n"
logging.warning(world.fish.translate("cli","cli","enemizer.nothing.applied")) enemizerMsg += world.fish.translate("cli","cli","enemizer.nothing.applied")
logging.warning(enemizerMsg)
raise EnemizerError(enemizerMsg)
if args.race: if args.race:
patch_race_rom(rom) patch_race_rom(rom)
@@ -255,19 +260,24 @@ def main(args, seed=None, fish=None):
with open(output_path('%s_multidata' % outfilebase), 'wb') as f: with open(output_path('%s_multidata' % outfilebase), 'wb') as f:
f.write(multidata) f.write(multidata)
if args.create_spoiler and not args.jsonout:
world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase))
if not args.skip_playthrough: if not args.skip_playthrough:
logger.info(world.fish.translate("cli","cli","calc.playthrough")) logger.info(world.fish.translate("cli","cli","calc.playthrough"))
create_playthrough(world) create_playthrough(world)
if args.jsonout: if args.jsonout:
print(json.dumps({**jsonout, 'spoiler': world.spoiler.to_json()})) print(json.dumps({**jsonout, 'spoiler': world.spoiler.to_json()}))
elif args.create_spoiler and not args.skip_playthrough: elif args.create_spoiler:
logger.info(world.fish.translate("cli","cli","patching.spoiler"))
world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase)) world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase))
YES = world.fish.translate("cli","cli","yes")
NO = world.fish.translate("cli","cli","no")
logger.info("")
logger.info(world.fish.translate("cli","cli","done")) logger.info(world.fish.translate("cli","cli","done"))
logger.info("")
logger.info(world.fish.translate("cli","cli","made.rom") % (YES if (args.create_rom) else NO))
logger.info(world.fish.translate("cli","cli","made.playthrough") % (YES if (args.calc_playthrough) else NO))
logger.info(world.fish.translate("cli","cli","made.spoiler") % (YES if (not args.jsonout and args.create_spoiler) else NO))
logger.info(world.fish.translate("cli","cli","seed") + ": %d", world.seed) logger.info(world.fish.translate("cli","cli","seed") + ": %d", world.seed)
logger.info(world.fish.translate("cli","cli","total.time"), time.perf_counter() - start) logger.info(world.fish.translate("cli","cli","total.time"), time.perf_counter() - start)

View File

@@ -5,7 +5,7 @@ import urllib.request
import urllib.parse import urllib.parse
import re import re
from DungeonRandomizer import parse_arguments from DungeonRandomizer import parse_cli
from Main import main as DRMain from Main import main as DRMain
def parse_yaml(txt): def parse_yaml(txt):
@@ -71,7 +71,7 @@ def main():
weights_cache[path] = get_weights(path) weights_cache[path] = get_weights(path)
print(f"P{player} Weights: {path} >> {weights_cache[path]['description']}") print(f"P{player} Weights: {path} >> {weights_cache[path]['description']}")
erargs = parse_arguments(['--multi', str(args.multi)]) erargs = parse_cli(['--multi', str(args.multi)])
erargs.seed = seed erargs.seed = seed
erargs.names = args.names erargs.names = args.names
erargs.create_spoiler = args.create_spoiler erargs.create_spoiler = args.create_spoiler

10
Rom.py
View File

@@ -78,6 +78,8 @@ class LocalRom(object):
self.name = name self.name = name
self.hash = hash self.hash = hash
self.orig_buffer = None self.orig_buffer = None
if not os.path.isfile(file):
raise RuntimeError("Could not find valid local base rom for patching at expected path %s." % args.rom)
with open(file, 'rb') as stream: with open(file, 'rb') as stream:
self.buffer = read_rom(stream) self.buffer = read_rom(stream)
if patch: if patch:
@@ -759,10 +761,10 @@ def patch_rom(world, rom, player, team, enemized):
difficulty.progressive_shield_limit, overflow_replacement, difficulty.progressive_shield_limit, overflow_replacement,
difficulty.progressive_armor_limit, overflow_replacement, difficulty.progressive_armor_limit, overflow_replacement,
difficulty.progressive_bottle_limit, overflow_replacement]) difficulty.progressive_bottle_limit, overflow_replacement])
#Work around for json patch ordering issues - write bow limit separately so that it is replaced in the patch #Work around for json patch ordering issues - write bow limit separately so that it is replaced in the patch
rom.write_bytes(0x180098, [difficulty.progressive_bow_limit, overflow_replacement]) rom.write_bytes(0x180098, [difficulty.progressive_bow_limit, overflow_replacement])
if difficulty.progressive_bow_limit < 2 and world.swords == 'swordless': if difficulty.progressive_bow_limit < 2 and world.swords == 'swordless':
rom.write_bytes(0x180098, [2, overflow_replacement]) rom.write_bytes(0x180098, [2, overflow_replacement])
rom.write_byte(0x180181, 0x01) # Make silver arrows work only on ganon rom.write_byte(0x180181, 0x01) # Make silver arrows work only on ganon
@@ -2089,9 +2091,9 @@ def patch_shuffled_dark_sanc(world, rom, player):
dark_sanc_entrance = str(world.get_region('Inverted Dark Sanctuary', player).entrances[0].name) dark_sanc_entrance = str(world.get_region('Inverted Dark Sanctuary', player).entrances[0].name)
room_id, ow_area, vram_loc, scroll_y, scroll_x, link_y, link_x, camera_y, camera_x, unknown_1, unknown_2, door_1, door_2 = door_addresses[dark_sanc_entrance][1] room_id, ow_area, vram_loc, scroll_y, scroll_x, link_y, link_x, camera_y, camera_x, unknown_1, unknown_2, door_1, door_2 = door_addresses[dark_sanc_entrance][1]
door_index = door_addresses[str(dark_sanc_entrance)][0] door_index = door_addresses[str(dark_sanc_entrance)][0]
rom.write_byte(0x180241, 0x01) rom.write_byte(0x180241, 0x01)
rom.write_byte(0x180248, door_index + 1) rom.write_byte(0x180248, door_index + 1)
write_int16(rom, 0x180250, room_id) write_int16(rom, 0x180250, room_id)
rom.write_byte(0x180252, ow_area) rom.write_byte(0x180252, ow_area)
write_int16s(rom, 0x180253, [vram_loc, scroll_y, scroll_x, link_y, link_x, camera_y, camera_x]) write_int16s(rom, 0x180253, [vram_loc, scroll_y, scroll_x, link_y, link_x, camera_y, camera_x])

View File

@@ -248,6 +248,38 @@ def print_wiki_doors_by_region(d_regions, world, player):
with open(os.path.join(".","resources", "user", "regions-" + d + ".txt"),"w+") as f: with open(os.path.join(".","resources", "user", "regions-" + d + ".txt"),"w+") as f:
f.write(toprint) f.write(toprint)
def update_deprecated_args(args):
argVars = vars(args)
truthy = [ 1, True, "True", "true" ]
# Don't do: Yes
# Do: No
if "suppress_rom" in argVars:
args.create_rom = args.suppress_rom not in truthy
# Don't do: No
# Do: Yes
if "create_rom" in argVars:
args.suppress_rom = not args.create_rom in truthy
# Don't do: Yes
# Do: No
if "no_shuffleganon" in argVars:
args.shuffleganon = not args.no_shuffleganon in truthy
# Don't do: No
# Do: Yes
if "shuffleganon" in argVars:
args.no_shuffleganon = not args.shuffleganon in truthy
# Don't do: Yes
# Do: No
if "skip_playthrough" in argVars:
args.calc_playthrough = not args.skip_playthrough in truthy
# Don't do: No
# Do: Yes
if "calc_playthrough" in argVars:
args.skip_playthrough = not args.calc_playthrough in truthy
return args
def print_wiki_doors_by_room(d_regions, world, player): def print_wiki_doors_by_room(d_regions, world, player):
for d, region_list in d_regions.items(): for d, region_list in d_regions.items():
tile_map = {} tile_map = {}

View File

@@ -107,10 +107,10 @@
}, },
"dungeon_counters": { "dungeon_counters": {
"choices": [ "choices": [
"default",
"off", "off",
"on", "on",
"pickup", "pickup"
"default"
] ]
}, },
"crystals_ganon": { "crystals_ganon": {
@@ -198,15 +198,6 @@
"action": "store_true", "action": "store_true",
"type": "bool" "type": "bool"
}, },
"shuffleganon": {
"action": "store_true",
"type": "bool"
},
"no-shuffleganon": {
"action": "store_false",
"dest": "shuffleganon",
"help": "suppress"
},
"heartbeep": { "heartbeep": {
"choices": [ "choices": [
"normal", "normal",
@@ -240,20 +231,39 @@
] ]
}, },
"sprite": {}, "sprite": {},
"create_rom": {
"action": "store_false",
"type": "bool"
},
"suppress_rom": { "suppress_rom": {
"action": "store_true", "action": "store_true",
"dest": "create_rom",
"help": "suppress"
},
"shuffleganon": {
"action": "store_false",
"type": "bool" "type": "bool"
}, },
"no_shuffleganon": {
"action": "store_true",
"dest": "shuffleganon",
"help": "suppress"
},
"calc_playthrough": {
"action": "store_false",
"type": "bool"
},
"skip_playthrough": {
"action": "store_true",
"dest": "calc_playthrough",
"help": "suppress"
},
"gui": { "gui": {
"action": "store_true" "action": "store_true"
}, },
"jsonout": { "jsonout": {
"action": "store_true" "action": "store_true"
}, },
"skip_playthrough": {
"action": "store_true",
"type": "bool"
},
"enemizercli": { "enemizercli": {
"setting": "enemizercli" "setting": "enemizercli"
}, },

View File

@@ -1,5 +1,7 @@
{ {
"cli": { "cli": {
"yes": "Yes",
"no": "No",
"app.title": "ALttP Door Randomizer Version %s - Seed: %d", "app.title": "ALttP Door Randomizer Version %s - Seed: %d",
"version": "Version", "version": "Version",
"seed": "Seed", "seed": "Seed",
@@ -33,7 +35,11 @@
"cannot.reach.progression": "Not all progression items reachable. Something went terribly wrong here.", "cannot.reach.progression": "Not all progression items reachable. Something went terribly wrong here.",
"cannot.reach.required": "Not all required items reachable. Something went terribly wrong here.", "cannot.reach.required": "Not all required items reachable. Something went terribly wrong here.",
"patching.rom": "Patching ROM", "patching.rom": "Patching ROM",
"patching.spoiler": "Creating Spoiler",
"calc.playthrough": "Calculating playthrough", "calc.playthrough": "Calculating playthrough",
"made.rom": "Patched ROM: %s",
"made.playthrough": "Printed Playthrough: %s",
"made.spoiler": "Printed Spoiler: %s",
"done": "Done. Enjoy.", "done": "Done. Enjoy.",
"total.time": "Total Time: %s", "total.time": "Total Time: %s",
"finished.run": "Finished run", "finished.run": "Finished run",
@@ -262,7 +268,7 @@
"Alternatively, can be a ALttP Rom patched with a Link", "Alternatively, can be a ALttP Rom patched with a Link",
"sprite that will be extracted." "sprite that will be extracted."
], ],
"suppress_rom": [ "Do not create an output rom file. (default: %(default)s)" ], "create_rom": [ "Create an output rom file. (default: %(default)s)" ],
"gui": [ "Launch the GUI. (default: %(default)s)" ], "gui": [ "Launch the GUI. (default: %(default)s)" ],
"jsonout": [ "jsonout": [
"Output .json patch to stdout instead of a patched rom. Used", "Output .json patch to stdout instead of a patched rom. Used",

View File

@@ -155,7 +155,8 @@
"randomizer.generation.spoiler": "Create Spoiler Log", "randomizer.generation.spoiler": "Create Spoiler Log",
"randomizer.generation.suppressrom": "Do Not create Patched ROM", "randomizer.generation.createrom": "Create Patched ROM",
"randomizer.generation.calcplaythrough": "Calculate Playthrough",
"randomizer.generation.usestartinventory": "Use Starting Inventory", "randomizer.generation.usestartinventory": "Use Starting Inventory",
"randomizer.generation.usecustompool": "Use Custom Item Pool", "randomizer.generation.usecustompool": "Use Custom Item Pool",

View File

@@ -1,7 +1,8 @@
{ {
"checkboxes": { "checkboxes": {
"spoiler": { "type": "checkbox" }, "spoiler": { "type": "checkbox" },
"suppressrom": { "type": "checkbox" }, "createrom": { "type": "checkbox" },
"calcplaythrough": { "type": "checkbox" },
"usestartinventory": { "type": "checkbox" }, "usestartinventory": { "type": "checkbox" },
"usecustompool": { "type": "checkbox" } "usecustompool": { "type": "checkbox" }
} }

View File

@@ -102,7 +102,8 @@ SETTINGSTOPROCESS = {
}, },
"generation": { "generation": {
"spoiler": "create_spoiler", "spoiler": "create_spoiler",
"suppressrom": "suppress_rom", "createrom": "create_rom",
"calcplaythrough": "calc_playthrough",
"usestartinventory": "usestartinventory", "usestartinventory": "usestartinventory",
"usecustompool": "custom", "usecustompool": "custom",
"saveonexit": "saveonexit" "saveonexit": "saveonexit"

View File

@@ -3,9 +3,10 @@ from argparse import Namespace
import logging import logging
import os import os
import random import random
from CLI import parse_arguments from CLI import parse_cli
from Main import main from Fill import FillError
from Utils import local_path, output_path, open_file from Main import main, EnemizerError
from Utils import local_path, output_path, open_file, update_deprecated_args
import source.classes.constants as CONST import source.classes.constants as CONST
from source.gui.randomize.multiworld import multiworld_page from source.gui.randomize.multiworld import multiworld_page
import source.gui.widgets as widgets import source.gui.widgets as widgets
@@ -68,7 +69,7 @@ def bottom_frame(self, parent, args=None):
def generateRom(): def generateRom():
guiargs = create_guiargs(parent) guiargs = create_guiargs(parent)
# get default values for missing parameters # get default values for missing parameters
for k,v in vars(parse_arguments(['--multi', str(guiargs.multi)])).items(): for k,v in vars(parse_cli(['--multi', str(guiargs.multi)])).items():
if k not in vars(guiargs): if k not in vars(guiargs):
setattr(guiargs, k, v) setattr(guiargs, k, v)
elif type(v) is dict: # use same settings for every player elif type(v) is dict: # use same settings for every player
@@ -81,11 +82,18 @@ def bottom_frame(self, parent, args=None):
seed = random.randint(0, 999999999) seed = random.randint(0, 999999999)
else: else:
main(seed=guiargs.seed, args=guiargs, fish=parent.fish) main(seed=guiargs.seed, args=guiargs, fish=parent.fish)
except Exception as e: except (FillError, EnemizerError, Exception, RuntimeError) as e:
logging.exception(e) logging.exception(e)
messagebox.showerror(title="Error while creating seed", message=str(e)) messagebox.showerror(title="Error while creating seed", message=str(e))
else: else:
messagebox.showinfo(title="Success", message="Rom patched successfully") YES = parent.fish.translate("cli","cli","yes")
NO = parent.fish.translate("cli","cli","no")
successMsg = ""
successMsg += (parent.fish.translate("cli","cli","made.rom").strip() % (YES if (guiargs.create_rom) else NO)) + "\n"
successMsg += (parent.fish.translate("cli","cli","made.playthrough").strip() % (YES if (guiargs.calc_playthrough) else NO)) + "\n"
successMsg += (parent.fish.translate("cli","cli","made.spoiler").strip() % (YES if (not guiargs.jsonout and guiargs.create_spoiler) else NO))
messagebox.showinfo(title="Success", message=successMsg)
## Generate Button ## Generate Button
# widget ID # widget ID
@@ -226,4 +234,7 @@ def create_guiargs(parent):
# Get output path # Get output path
guiargs.outputpath = parent.outputPath.get() guiargs.outputpath = parent.outputPath.get()
guiargs = update_deprecated_args(guiargs)
return guiargs return guiargs

View File

@@ -1,6 +1,7 @@
from source.classes.SpriteSelector import SpriteSelector as spriteSelector from source.classes.SpriteSelector import SpriteSelector as spriteSelector
from source.gui.randomize.gameoptions import set_sprite from source.gui.randomize.gameoptions import set_sprite
from Rom import Sprite, get_sprite_from_name from Rom import Sprite, get_sprite_from_name
from Utils import update_deprecated_args
import source.classes.constants as CONST import source.classes.constants as CONST
from source.classes.BabelFish import BabelFish from source.classes.BabelFish import BabelFish
from source.classes.Empty import Empty from source.classes.Empty import Empty
@@ -8,10 +9,12 @@ from source.classes.Empty import Empty
# Load args/settings for most tabs # Load args/settings for most tabs
def loadcliargs(gui, args, settings=None): def loadcliargs(gui, args, settings=None):
if args is not None: if args is not None:
args = update_deprecated_args(args)
args = vars(args)
fish = BabelFish() fish = BabelFish()
# for k, v in vars(args).items(): for k, v in args.items():
# if type(v) is dict: if isinstance(v,dict) and 1 in v:
# setattr(args, k, v[1]) # only get values for player 1 for now setattr(args, k, v[1]) # only get values for player 1 for now
# load values from commandline args # load values from commandline args
# set up options to get # set up options to get