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:
69
CLI.py
69
CLI.py
@@ -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
|
||||||
|
|||||||
@@ -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
16
Gui.py
@@ -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)
|
||||||
|
|||||||
10
ItemList.py
10
ItemList.py
@@ -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
26
Main.py
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
10
Rom.py
@@ -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])
|
||||||
|
|||||||
32
Utils.py
32
Utils.py
@@ -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 = {}
|
||||||
|
|||||||
@@ -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"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|
||||||
|
|||||||
@@ -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" }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user