2018-01-01 18:11:11 +00:00
#!/usr/bin/env python3
2017-07-14 12:34:33 +00:00
import argparse
2019-12-16 11:52:30 +00:00
import copy
2017-07-14 12:34:33 +00:00
import os
import logging
2017-07-14 16:24:23 +00:00
import textwrap
2019-12-16 11:52:30 +00:00
import shlex
2017-11-19 21:00:26 +00:00
import sys
2017-07-14 12:34:33 +00:00
2020-06-27 22:24:45 +00:00
from Main import main , get_seed
2020-10-24 03:33:52 +00:00
from Rom import Sprite
2019-12-28 16:12:27 +00:00
from Utils import is_bundled , close_console
2017-07-14 12:34:33 +00:00
2017-07-14 16:24:23 +00:00
class ArgumentDefaultsHelpFormatter ( argparse . RawTextHelpFormatter ) :
def _get_help_string ( self , action ) :
return textwrap . dedent ( action . help )
2019-12-15 17:10:01 +00:00
def parse_arguments ( argv , no_defaults = False ) :
def defval ( value ) :
return value if not no_defaults else None
2017-11-04 18:23:57 +00:00
2019-12-16 11:52:30 +00:00
# we need to know how many players we have first
2019-12-30 19:43:43 +00:00
parser = argparse . ArgumentParser ( add_help = False )
2019-12-16 11:52:30 +00:00
parser . add_argument ( ' --multi ' , default = defval ( 1 ) , type = lambda value : min ( max ( int ( value ) , 1 ) , 255 ) )
multiargs , _ = parser . parse_known_args ( argv )
2017-07-14 16:24:23 +00:00
parser = argparse . ArgumentParser ( formatter_class = ArgumentDefaultsHelpFormatter )
2017-07-14 12:34:33 +00:00
parser . add_argument ( ' --create_spoiler ' , help = ' Output a Spoiler File ' , action = ' store_true ' )
2020-01-03 08:02:15 +00:00
parser . add_argument ( ' --logic ' , default = defval ( ' noglitches ' ) , const = ' noglitches ' , nargs = ' ? ' , choices = [ ' noglitches ' , ' minorglitches ' , ' owglitches ' , ' nologic ' ] ,
2017-07-14 16:24:23 +00:00
help = ''' \
Select Enforcement of Item Requirements . ( default : % ( default ) s )
2017-11-19 01:43:37 +00:00
No Glitches :
2017-07-14 16:24:23 +00:00
Minor Glitches : May require Fake Flippers , Bunny Revival
2017-11-19 01:43:37 +00:00
and Dark Room Navigation .
2020-04-14 05:02:43 +00:00
Overworld Glitches : May require overworld glitches .
2018-03-25 22:21:36 +00:00
No Logic : Distribute items without regard for
2020-04-14 05:02:43 +00:00
item requirements .
2017-07-14 16:24:23 +00:00
''' )
2019-12-15 17:10:01 +00:00
parser . add_argument ( ' --mode ' , default = defval ( ' open ' ) , const = ' open ' , nargs = ' ? ' , choices = [ ' standard ' , ' open ' , ' inverted ' ] ,
2017-07-14 16:24:23 +00:00
help = ''' \
Select game mode . ( default : % ( default ) s )
2017-07-17 20:28:29 +00:00
Open : World starts with Zelda rescued .
2017-07-14 16:24:23 +00:00
Standard : Fixes Hyrule Castle Secret Entrance and Front Door
but may lead to weird rain state issues if you exit
through the Hyrule Castle side exits before rescuing
Zelda in a full shuffle .
2019-07-27 13:13:13 +00:00
Inverted : Starting locations are Dark Sanctuary in West Dark
World or at Link ' s House, which is shuffled freely.
Requires the moon pearl to be Link in the Light World
instead of a bunny .
2017-07-14 16:24:23 +00:00
''' )
2019-12-15 17:10:01 +00:00
parser . add_argument ( ' --swords ' , default = defval ( ' random ' ) , const = ' random ' , nargs = ' ? ' , choices = [ ' random ' , ' assured ' , ' swordless ' , ' vanilla ' ] ,
2019-08-04 16:32:35 +00:00
help = ''' \
Select sword placement . ( default : % ( default ) s )
Random : All swords placed randomly .
Assured : Start game with a sword already .
Swordless : No swords . Curtains in Skull Woods and Agahnim \' s
Tower are removed , Agahnim \' s Tower barrier can be
destroyed with hammer . Misery Mire and Turtle Rock
can be opened without a sword . Hammer damages Ganon .
Ether and Bombos Tablet can be activated with Hammer
( and Book ) . Bombos pads have been added in Ice
Palace , to allow for an alternative to firerod .
Vanilla : Swords are in vanilla locations .
''' )
2020-06-03 00:19:16 +00:00
parser . add_argument ( ' --goal ' , default = defval ( ' ganon ' ) , const = ' ganon ' , nargs = ' ? ' ,
2020-10-15 22:24:52 +00:00
choices = [ ' ganon ' , ' pedestal ' , ' dungeons ' , ' triforcehunt ' , ' localtriforcehunt ' , ' ganontriforcehunt ' , ' localganontriforcehunt ' , ' crystals ' , ' ganonpedestal ' ] ,
2017-07-14 16:24:23 +00:00
help = ''' \
Select completion goal . ( default : % ( default ) s )
2017-11-19 01:43:37 +00:00
Ganon : Collect all crystals , beat Agahnim 2 then
2017-07-17 20:28:29 +00:00
defeat Ganon .
2017-08-01 17:07:44 +00:00
Crystals : Collect all crystals then defeat Ganon .
2017-07-14 16:24:23 +00:00
Pedestal : Places the Triforce at the Master Sword Pedestal .
2020-10-15 22:41:03 +00:00
Ganon Pedestal : Pull the Master Sword Pedestal , then defeat Ganon .
2017-07-17 20:28:29 +00:00
All Dungeons : Collect all crystals , pendants , beat both
Agahnim fights and then defeat Ganon .
2017-11-19 01:43:37 +00:00
Triforce Hunt : Places 30 Triforce Pieces in the world , collect
20 of them to beat the game .
2020-06-03 00:19:16 +00:00
Local Triforce Hunt : Places 30 Triforce Pieces in your world , collect
2020-06-26 14:18:53 +00:00
20 of them to beat the game .
Ganon Triforce Hunt : Places 30 Triforce Pieces in the world , collect
20 of them , then defeat Ganon .
Local Ganon Triforce Hunt : Places 30 Triforce Pieces in your world ,
collect 20 of them , then defeat Ganon .
2017-07-14 16:24:23 +00:00
''' )
2020-06-17 08:02:54 +00:00
parser . add_argument ( ' --triforce_pieces_available ' , default = defval ( 30 ) ,
2020-06-18 15:48:33 +00:00
type = lambda value : min ( max ( int ( value ) , 1 ) , 90 ) ,
2020-06-17 08:02:54 +00:00
help = ''' Set Triforce Pieces available in item pool. ''' )
2020-06-07 13:22:24 +00:00
parser . add_argument ( ' --triforce_pieces_required ' , default = defval ( 20 ) ,
2020-06-18 15:48:33 +00:00
type = lambda value : min ( max ( int ( value ) , 1 ) , 90 ) ,
2020-06-07 13:22:24 +00:00
help = ''' Set Triforce Pieces required to win a Triforce Hunt ''' )
parser . add_argument ( ' --difficulty ' , default = defval ( ' normal ' ) , const = ' normal ' , nargs = ' ? ' ,
2020-08-01 14:49:46 +00:00
choices = [ ' easy ' , ' normal ' , ' hard ' , ' expert ' ] ,
2017-07-14 16:24:23 +00:00
help = ''' \
Select game difficulty . Affects available itempool . ( default : % ( default ) s )
2020-08-01 14:49:46 +00:00
Easy : An easier setting with some equipment duplicated and increased health .
2017-07-14 16:24:23 +00:00
Normal : Normal difficulty .
2017-11-10 10:18:09 +00:00
Hard : A harder setting with less equipment and reduced health .
Expert : A harder yet setting with minimum equipment and health .
''' )
2020-06-07 13:22:24 +00:00
parser . add_argument ( ' --item_functionality ' , default = defval ( ' normal ' ) , const = ' normal ' , nargs = ' ? ' ,
2020-09-17 05:00:27 +00:00
choices = [ ' easy ' , ' normal ' , ' hard ' , ' expert ' ] ,
2020-06-07 13:22:24 +00:00
help = ''' \
2019-08-10 23:37:26 +00:00
Select limits on item functionality to increase difficulty . ( default : % ( default ) s )
2020-09-17 05:00:27 +00:00
Easy : Easy functionality . ( Medallions usable without sword )
2019-08-10 23:37:26 +00:00
Normal : Normal functionality .
Hard : Reduced functionality .
Expert : Greatly reduced functionality .
''' )
2019-12-15 17:10:01 +00:00
parser . add_argument ( ' --timer ' , default = defval ( ' none ' ) , const = ' normal ' , nargs = ' ? ' , choices = [ ' none ' , ' display ' , ' timed ' , ' timed-ohko ' , ' ohko ' , ' timed-countdown ' ] ,
2017-11-10 10:18:09 +00:00
help = ''' \
Select game timer setting . Affects available itempool . ( default : % ( default ) s )
None : No timer .
2017-11-12 00:08:41 +00:00
Display : Displays a timer but does not affect
the itempool .
2017-07-14 16:24:23 +00:00
Timed : Starts with clock at zero . Green Clocks
subtract 4 minutes ( Total : 20 ) , Blue Clocks
subtract 2 minutes ( Total : 10 ) , Red Clocks add
2 minutes ( Total : 10 ) . Winner is player with
lowest time at the end .
Timed OHKO : Starts clock at 10 minutes . Green Clocks add
5 minutes ( Total : 25 ) . As long as clock is at 0 ,
Link will die in one hit .
2017-11-19 01:36:42 +00:00
OHKO : Like Timed OHKO , but no clock items are present
and the clock is permenantly at zero .
2017-07-14 16:24:23 +00:00
Timed Countdown : Starts with clock at 40 minutes . Same clocks as
Timed mode . If time runs out , you lose ( but can
2017-11-19 01:43:37 +00:00
still keep playing ) .
2017-07-14 16:24:23 +00:00
''' )
2020-10-28 23:20:59 +00:00
parser . add_argument ( ' --countdown_start_time ' , default = defval ( 10 ) , type = int ,
help = ''' Set amount of time, in minutes, to start with in Timed Countdown and Timed OHKO modes ''' )
parser . add_argument ( ' --red_clock_time ' , default = defval ( - 2 ) , type = int ,
help = ''' Set amount of time, in minutes, to add from picking up red clocks; negative removes time instead ''' )
parser . add_argument ( ' --blue_clock_time ' , default = defval ( 2 ) , type = int ,
help = ''' Set amount of time, in minutes, to add from picking up blue clocks; negative removes time instead ''' )
parser . add_argument ( ' --green_clock_time ' , default = defval ( 4 ) , type = int ,
help = ''' Set amount of time, in minutes, to add from picking up green clocks; negative removes time instead ''' )
2020-04-12 22:46:32 +00:00
parser . add_argument ( ' --dungeon_counters ' , default = defval ( ' default ' ) , const = ' default ' , nargs = ' ? ' , choices = [ ' default ' , ' on ' , ' pickup ' , ' off ' ] ,
help = ''' \
Select dungeon counter display settings . ( default : % ( default ) s )
( Note , since timer takes up the same space on the hud as dungeon
counters , timer settings override dungeon counter settings . )
Default : Dungeon counters only show when the compass is
picked up , or otherwise sent , only when compass
shuffle is turned on .
On : Dungeon counters are always displayed .
Pickup : Dungeon counters are shown when the compass is
picked up , even when compass shuffle is turned
off .
Off : Dungeon counters are never shown .
''' )
2019-12-15 17:10:01 +00:00
parser . add_argument ( ' --progressive ' , default = defval ( ' on ' ) , const = ' normal ' , nargs = ' ? ' , choices = [ ' on ' , ' off ' , ' random ' ] ,
2017-11-10 10:18:09 +00:00
help = ''' \
Select progressive equipment setting . Affects available itempool . ( default : % ( default ) s )
On : Swords , Shields , Armor , and Gloves will
all be progressive equipment . Each subsequent
item of the same type the player finds will
upgrade that piece of equipment by one stage .
Off : Swords , Shields , Armor , and Gloves will not
be progressive equipment . Higher level items may
be found at any time . Downgrades are not possible .
Random : Swords , Shields , Armor , and Gloves will , per
category , be randomly progressive or not .
2017-11-19 01:43:37 +00:00
Link will die in one hit .
2017-11-10 10:18:09 +00:00
''' )
2020-08-25 15:44:03 +00:00
parser . add_argument ( ' --algorithm ' , default = defval ( ' balanced ' ) , const = ' balanced ' , nargs = ' ? ' ,
choices = [ ' freshness ' , ' flood ' , ' vt25 ' , ' vt26 ' , ' balanced ' ] ,
2017-07-14 16:24:23 +00:00
help = ''' \
2017-10-15 17:52:42 +00:00
Select item filling algorithm . ( default : % ( default ) s
2017-11-11 21:28:34 +00:00
balanced : vt26 derivitive that aims to strike a balance between
the overworld heavy vt25 and the dungeon heavy vt26
algorithm .
2017-10-15 17:52:42 +00:00
vt26 : Shuffle items and place them in a random location
that it is not impossible to be in . This includes
2017-11-11 21:28:34 +00:00
dungeon keys and items .
2017-08-01 17:07:44 +00:00
vt25 : Shuffle items and place them in a random location
2017-07-14 16:24:23 +00:00
that it is not impossible to be in .
Flood : Push out items starting from Link \' s House and
slightly biased to placing progression items with
2017-11-19 01:43:37 +00:00
less restrictions .
2017-07-14 16:24:23 +00:00
''' )
2020-11-13 23:46:29 +00:00
parser . add_argument ( ' --shuffle ' , default = defval ( ' vanilla ' ) , const = ' vanilla ' , nargs = ' ? ' , choices = [ ' vanilla ' , ' simple ' , ' restricted ' , ' full ' , ' crossed ' , ' insanity ' , ' restricted_legacy ' , ' full_legacy ' , ' madness_legacy ' , ' insanity_legacy ' , ' dungeonsfull ' , ' dungeonssimple ' ] ,
2017-07-14 16:24:23 +00:00
help = ''' \
Select Entrance Shuffling Algorithm . ( default : % ( default ) s )
2018-02-20 20:34:39 +00:00
Full : Mix cave and dungeon entrances freely while limiting
multi - entrance caves to one world .
2017-07-14 16:24:23 +00:00
Simple : Shuffle Dungeon Entrances / Exits between each other
and keep all 4 - entrance dungeons confined to one
location . All caves outside of death mountain are
2018-02-20 20:34:39 +00:00
shuffled in pairs and matched by original type .
2017-07-14 16:24:23 +00:00
Restricted : Use Dungeons shuffling from Simple but freely
connect remaining entrances .
2018-02-20 20:34:39 +00:00
Crossed : Mix cave and dungeon entrances freely while allowing
caves to cross between worlds .
Insanity : Decouple entrances and exits from each other and
shuffle them freely . Caves that used to be single
entrance will still exit to the same location from
which they are entered .
Vanilla : All entrances are in the same locations they were
in the base game .
Legacy shuffles preserve behavior from older versions of the
entrance randomizer including significant technical limitations .
2017-07-14 16:24:23 +00:00
The dungeon variants only mix up dungeons and keep the rest of
2017-11-19 01:43:37 +00:00
the overworld vanilla .
2017-07-14 16:24:23 +00:00
''' )
2019-12-15 17:10:01 +00:00
parser . add_argument ( ' --crystals_ganon ' , default = defval ( ' 7 ' ) , const = ' 7 ' , nargs = ' ? ' , choices = [ ' random ' , ' 0 ' , ' 1 ' , ' 2 ' , ' 3 ' , ' 4 ' , ' 5 ' , ' 6 ' , ' 7 ' ] ,
2019-08-11 12:55:38 +00:00
help = ''' \
How many crystals are needed to defeat ganon . Any other
requirements for ganon for the selected goal still apply .
This setting does not apply when the all dungeons goal is
selected . ( default : % ( default ) s )
Random : Picks a random value between 0 and 7 ( inclusive ) .
0 - 7 : Number of crystals needed
''' )
2020-09-11 01:23:00 +00:00
parser . add_argument ( ' --crystals_gt ' , default = defval ( ' 7 ' ) , const = ' 7 ' , nargs = ' ? ' ,
choices = [ ' random ' , ' 0 ' , ' 1 ' , ' 2 ' , ' 3 ' , ' 4 ' , ' 5 ' , ' 6 ' , ' 7 ' ] ,
2019-08-11 12:55:38 +00:00
help = ''' \
How many crystals are needed to open GT . For inverted mode
this applies to the castle tower door instead . ( default : % ( default ) s )
Random : Picks a random value between 0 and 7 ( inclusive ) .
0 - 7 : Number of crystals needed
''' )
2020-09-11 01:23:00 +00:00
parser . add_argument ( ' --open_pyramid ' , default = defval ( False ) , help = ''' \
2019-12-12 08:20:32 +00:00
Pre - opens the pyramid hole , this removes the Agahnim 2 requirement for it
''' , action= ' store_true ' )
2020-09-11 01:23:00 +00:00
parser . add_argument ( ' --rom ' , default = defval ( ' Zelda no Densetsu - Kamigami no Triforce (Japan).sfc ' ) ,
help = ' Path to an ALttP JAP(1.0) rom to use as a base. ' )
2019-12-15 17:10:01 +00:00
parser . add_argument ( ' --loglevel ' , default = defval ( ' info ' ) , const = ' info ' , nargs = ' ? ' , choices = [ ' error ' , ' info ' , ' warning ' , ' debug ' ] , help = ' Select level of logging for output. ' )
2017-07-14 12:34:33 +00:00
parser . add_argument ( ' --seed ' , help = ' Define seed number to generate. ' , type = int )
2017-07-14 16:24:23 +00:00
parser . add_argument ( ' --count ' , help = ''' \
Use to batch generate multiple seeds with same settings .
If - - seed is provided , it will be used for the first seed , then
used to derive the next seed ( i . e . generating 10 seeds with
- - seed given will produce the same 10 ( different ) roms each
2017-11-19 01:43:37 +00:00
time ) .
2017-07-14 16:24:23 +00:00
''' , type=int)
2020-08-20 18:13:00 +00:00
parser . add_argument ( ' --fastmenu ' , default = defval ( ' normal ' ) , const = ' normal ' , nargs = ' ? ' ,
choices = [ ' normal ' , ' instant ' , ' double ' , ' triple ' , ' quadruple ' , ' half ' ] ,
2018-01-05 22:53:29 +00:00
help = ''' \
Select the rate at which the menu opens and closes .
( default : % ( default ) s )
''' )
2017-07-14 12:34:33 +00:00
parser . add_argument ( ' --quickswap ' , help = ' Enable quick item swapping with L and R. ' , action = ' store_true ' )
2017-11-28 10:54:14 +00:00
parser . add_argument ( ' --disablemusic ' , help = ' Disables game music. ' , action = ' store_true ' )
2020-08-20 18:13:00 +00:00
parser . add_argument ( ' --mapshuffle ' , default = defval ( False ) ,
help = ' Maps are no longer restricted to their dungeons, but can be anywhere ' ,
action = ' store_true ' )
parser . add_argument ( ' --compassshuffle ' , default = defval ( False ) ,
help = ' Compasses are no longer restricted to their dungeons, but can be anywhere ' ,
action = ' store_true ' )
parser . add_argument ( ' --keyshuffle ' , default = defval ( " off " ) , help = ' \
on : Small Keys are no longer restricted to their dungeons , but can be anywhere . \
universal : Makes all Small Keys usable in any dungeon and places shops to buy more keys . ' ,
choices = [ " on " , " universal " , " off " ] )
parser . add_argument ( ' --bigkeyshuffle ' , default = defval ( False ) ,
help = ' Big Keys are no longer restricted to their dungeons, but can be anywhere ' ,
action = ' store_true ' )
2020-01-01 17:42:36 +00:00
parser . add_argument ( ' --keysanity ' , default = defval ( False ) , help = argparse . SUPPRESS , action = ' store_true ' )
2019-12-27 18:10:40 +00:00
parser . add_argument ( ' --retro ' , default = defval ( False ) , help = ''' \
2018-03-14 18:31:36 +00:00
Keys are universal , shooting arrows costs rupees ,
and a few other little things make this more like Zelda - 1.
''' , action= ' store_true ' )
2020-06-03 20:13:58 +00:00
parser . add_argument ( ' --startinventory ' , default = defval ( ' ' ) ,
help = ' Specifies a list of items that will be in your starting inventory (separated by commas) ' )
parser . add_argument ( ' --local_items ' , default = defval ( ' ' ) ,
help = ' Specifies a list of items that will not spread across the multiworld (separated by commas) ' )
2020-11-22 21:53:31 +00:00
parser . add_argument ( ' --non_local_items ' , default = defval ( ' ' ) ,
2020-11-22 21:55:31 +00:00
help = ' Specifies a list of items that will spread across the multiworld (separated by commas) ' )
2019-12-15 17:10:01 +00:00
parser . add_argument ( ' --custom ' , default = defval ( False ) , help = ' Not supported. ' )
parser . add_argument ( ' --customitemarray ' , default = defval ( False ) , help = ' Not supported. ' )
parser . add_argument ( ' --accessibility ' , default = defval ( ' items ' ) , const = ' items ' , nargs = ' ? ' , choices = [ ' items ' , ' locations ' , ' none ' ] , help = ''' \
2019-08-04 21:40:13 +00:00
Select Item / Location Accessibility . ( default : % ( default ) s )
Items : You can reach all unique inventory items . No guarantees about
reaching all locations or all keys .
Locations : You will be able to reach every location in the game .
None : You will be able to reach enough locations to beat the game .
''' )
2019-12-27 18:10:40 +00:00
parser . add_argument ( ' --hints ' , default = defval ( False ) , help = ''' \
2019-01-23 09:04:42 +00:00
Make telepathic tiles and storytellers give helpful hints .
''' , action= ' store_true ' )
2018-01-27 22:11:53 +00:00
# included for backwards compatibility
2019-12-15 17:10:01 +00:00
parser . add_argument ( ' --shuffleganon ' , help = argparse . SUPPRESS , action = ' store_true ' , default = defval ( True ) )
2018-01-27 22:11:53 +00:00
parser . add_argument ( ' --no-shuffleganon ' , help = ''' \
If set , the Pyramid Hole and Ganon ' s Tower are not
included entrance shuffle pool .
''' , action= ' store_false ' , dest= ' shuffleganon ' )
2019-12-15 17:10:01 +00:00
parser . add_argument ( ' --heartbeep ' , default = defval ( ' normal ' ) , const = ' normal ' , nargs = ' ? ' , choices = [ ' double ' , ' normal ' , ' half ' , ' quarter ' , ' off ' ] ,
2017-07-14 16:24:23 +00:00
help = ''' \
Select the rate at which the heart beep sound is played at
2017-11-19 01:43:37 +00:00
low health . ( default : % ( default ) s )
2017-07-14 16:24:23 +00:00
''' )
2019-12-15 17:10:01 +00:00
parser . add_argument ( ' --heartcolor ' , default = defval ( ' red ' ) , const = ' red ' , nargs = ' ? ' , choices = [ ' red ' , ' blue ' , ' green ' , ' yellow ' , ' random ' ] ,
2018-02-28 02:26:33 +00:00
help = ' Select the color of Link \' s heart meter. (default: %(default)s ) ' )
2020-10-24 00:44:27 +00:00
parser . add_argument ( ' --ow_palettes ' , default = defval ( ' default ' ) , choices = [ ' default ' , ' random ' , ' blackout ' , ' puke ' , ' classic ' , ' grayscale ' , ' negative ' , ' dizzy ' , ' sick ' ] )
parser . add_argument ( ' --uw_palettes ' , default = defval ( ' default ' ) , choices = [ ' default ' , ' random ' , ' blackout ' , ' puke ' , ' classic ' , ' grayscale ' , ' negative ' , ' dizzy ' , ' sick ' ] )
parser . add_argument ( ' --hud_palettes ' , default = defval ( ' default ' ) , choices = [ ' default ' , ' random ' , ' blackout ' , ' puke ' , ' classic ' , ' grayscale ' , ' negative ' , ' dizzy ' , ' sick ' ] )
parser . add_argument ( ' --shield_palettes ' , default = defval ( ' default ' ) , choices = [ ' default ' , ' random ' , ' blackout ' , ' puke ' , ' classic ' , ' grayscale ' , ' negative ' , ' dizzy ' , ' sick ' ] )
parser . add_argument ( ' --sword_palettes ' , default = defval ( ' default ' ) , choices = [ ' default ' , ' random ' , ' blackout ' , ' puke ' , ' classic ' , ' grayscale ' , ' negative ' , ' dizzy ' , ' sick ' ] )
parser . add_argument ( ' --link_palettes ' , default = defval ( ' default ' ) , choices = [ ' default ' , ' random ' , ' blackout ' , ' puke ' , ' classic ' , ' grayscale ' , ' negative ' , ' dizzy ' , ' sick ' ] )
2017-07-14 16:24:23 +00:00
parser . add_argument ( ' --sprite ' , help = ''' \
Path to a sprite sheet to use for Link . Needs to be in
2017-11-19 01:43:37 +00:00
binary format and have a length of 0x7000 ( 28672 ) bytes ,
2017-07-14 16:24:23 +00:00
or 0x7078 ( 28792 ) bytes including palette data .
Alternatively , can be a ALttP Rom patched with a Link
2017-11-19 01:43:37 +00:00
sprite that will be extracted .
2017-07-14 16:24:23 +00:00
''' )
2017-07-14 12:34:33 +00:00
parser . add_argument ( ' --suppress_rom ' , help = ' Do not create an output rom file. ' , action = ' store_true ' )
parser . add_argument ( ' --gui ' , help = ' Launch the GUI ' , action = ' store_true ' )
2020-05-11 00:17:18 +00:00
parser . add_argument ( ' --skip_progression_balancing ' , action = ' store_true ' , default = defval ( False ) ,
help = " Skip Multiworld Progression balancing. " )
2019-12-15 17:10:01 +00:00
parser . add_argument ( ' --skip_playthrough ' , action = ' store_true ' , default = defval ( False ) )
2020-01-06 17:39:18 +00:00
parser . add_argument ( ' --enemizercli ' , default = defval ( ' EnemizerCLI/EnemizerCLI.Core ' ) )
2020-07-30 22:07:55 +00:00
parser . add_argument ( ' --shufflebosses ' , default = defval ( ' none ' ) , choices = [ ' none ' , ' basic ' , ' normal ' , ' chaos ' ,
2020-08-19 19:10:02 +00:00
" singularity " ] )
2020-08-19 21:24:17 +00:00
parser . add_argument ( ' --enemy_shuffle ' , action = ' store_true ' )
parser . add_argument ( ' --killable_thieves ' , action = ' store_true ' )
parser . add_argument ( ' --tile_shuffle ' , action = ' store_true ' )
parser . add_argument ( ' --bush_shuffle ' , action = ' store_true ' )
2020-07-05 01:12:28 +00:00
parser . add_argument ( ' --enemy_health ' , default = defval ( ' default ' ) ,
choices = [ ' default ' , ' easy ' , ' normal ' , ' hard ' , ' expert ' ] )
2019-12-15 17:10:01 +00:00
parser . add_argument ( ' --enemy_damage ' , default = defval ( ' default ' ) , choices = [ ' default ' , ' shuffled ' , ' chaos ' ] )
parser . add_argument ( ' --shufflepots ' , default = defval ( False ) , action = ' store_true ' )
2019-12-30 02:03:53 +00:00
parser . add_argument ( ' --beemizer ' , default = defval ( 0 ) , type = lambda value : min ( max ( int ( value ) , 0 ) , 4 ) )
2020-08-23 19:38:21 +00:00
parser . add_argument ( ' --shop_shuffle ' , default = ' ' , help = ''' \
combine letters for options :
i : shuffle the inventories of the shops around
p : randomize the prices of the items in shop inventories
u : shuffle capacity upgrades into the item pool
''' )
2020-09-20 02:35:45 +00:00
parser . add_argument ( ' --shuffle_prizes ' , default = defval ( ' g ' ) , choices = [ ' ' , ' g ' , ' b ' , ' gb ' ] )
2020-10-06 20:22:03 +00:00
parser . add_argument ( ' --sprite_pool ' , help = ''' \
Specifies a colon separated list of sprites used for random / randomonevent . If not specified , the full sprite pool is used . ''' )
2020-10-07 17:51:46 +00:00
parser . add_argument ( ' --dark_room_logic ' , default = ( ' Lamp ' ) , choices = [ " lamp " , " torches " , " none " ] , help = ''' \
For unlit dark rooms , require the Lamp to be considered in logic by default .
Torches means additionally easily accessible Torches that can be lit with Fire Rod are considered doable .
None means full traversal through dark rooms without tools is considered doable . ''' )
parser . add_argument ( ' --restrict_dungeon_item_on_boss ' , default = defval ( False ) , action = " store_true " )
2020-01-18 08:50:12 +00:00
parser . add_argument ( ' --remote_items ' , default = defval ( False ) , action = ' store_true ' )
2019-12-15 17:10:01 +00:00
parser . add_argument ( ' --multi ' , default = defval ( 1 ) , type = lambda value : min ( max ( int ( value ) , 1 ) , 255 ) )
parser . add_argument ( ' --names ' , default = defval ( ' ' ) )
2020-01-14 09:42:27 +00:00
parser . add_argument ( ' --teams ' , default = defval ( 1 ) , type = lambda value : max ( int ( value ) , 1 ) )
2019-04-18 09:23:24 +00:00
parser . add_argument ( ' --outputpath ' )
2019-12-15 17:10:01 +00:00
parser . add_argument ( ' --race ' , default = defval ( False ) , action = ' store_true ' )
2019-12-15 16:29:17 +00:00
parser . add_argument ( ' --outputname ' )
2020-03-08 14:34:35 +00:00
parser . add_argument ( ' --create_diff ' , default = defval ( False ) , action = ' store_true ' , help = ''' \
2020-06-09 19:52:46 +00:00
create a binary patch file from which the randomized rom can be recreated using MultiClient . ''' )
2020-04-16 09:02:16 +00:00
parser . add_argument ( ' --disable_glitch_boots ' , default = defval ( False ) , action = ' store_true ' , help = ''' \
turns off starting with Pegasus Boots in glitched modes . ''' )
2019-12-16 11:52:30 +00:00
if multiargs . multi :
for player in range ( 1 , multiargs . multi + 1 ) :
parser . add_argument ( f ' --p { player } ' , default = defval ( ' ' ) , help = argparse . SUPPRESS )
ret = parser . parse_args ( argv )
2021-01-02 11:49:43 +00:00
# cannot be set through CLI currently
2021-01-02 15:44:58 +00:00
ret . plando_items = [ ]
ret . plando_texts = { }
2021-01-02 21:41:03 +00:00
ret . plando_connections = [ ]
2021-01-02 11:49:43 +00:00
2020-04-16 09:02:16 +00:00
ret . glitch_boots = not ret . disable_glitch_boots
2020-03-04 12:55:03 +00:00
if ret . timer == " none " :
ret . timer = False
2020-04-12 22:46:32 +00:00
if ret . dungeon_counters == ' on ' :
ret . dungeon_counters = True
elif ret . dungeon_counters == ' off ' :
ret . dungeon_counters = False
2019-12-16 11:52:30 +00:00
2020-08-20 18:13:00 +00:00
if ret . keysanity :
ret . mapshuffle = ret . compassshuffle = ret . keyshuffle = ret . bigkeyshuffle = True
elif ret . keyshuffle == " on " :
ret . keyshuffle = True
elif ret . keyshuffle == " off " :
ret . keyshuffle = False
2019-12-16 11:52:30 +00:00
if multiargs . multi :
defaults = copy . deepcopy ( ret )
for player in range ( 1 , multiargs . multi + 1 ) :
2020-03-04 12:55:03 +00:00
playerargs = parse_arguments ( shlex . split ( getattr ( ret , f " p { player } " ) ) , True )
2019-12-16 11:52:30 +00:00
2019-12-16 20:46:47 +00:00
for name in [ ' logic ' , ' mode ' , ' swords ' , ' goal ' , ' difficulty ' , ' item_functionality ' ,
2020-09-11 01:23:00 +00:00
' shuffle ' , ' crystals_ganon ' , ' crystals_gt ' , ' open_pyramid ' , ' timer ' ,
2020-10-28 23:20:59 +00:00
' countdown_start_time ' , ' red_clock_time ' , ' blue_clock_time ' , ' green_clock_time ' ,
2020-01-06 18:13:42 +00:00
' mapshuffle ' , ' compassshuffle ' , ' keyshuffle ' , ' bigkeyshuffle ' , ' startinventory ' ,
2020-11-22 21:53:31 +00:00
' local_items ' , ' non_local_items ' , ' retro ' , ' accessibility ' , ' hints ' , ' beemizer ' ,
2020-08-19 21:24:17 +00:00
' shufflebosses ' , ' enemy_shuffle ' , ' enemy_health ' , ' enemy_damage ' , ' shufflepots ' ,
2020-01-22 05:28:58 +00:00
' ow_palettes ' , ' uw_palettes ' , ' sprite ' , ' disablemusic ' , ' quickswap ' , ' fastmenu ' , ' heartcolor ' ,
2020-08-19 21:24:17 +00:00
' heartbeep ' , " skip_progression_balancing " , " triforce_pieces_available " ,
2021-01-02 21:41:03 +00:00
" triforce_pieces_required " , " shop_shuffle " ,
" plando_items " , " plando_texts " , " plando_connections " ,
2020-08-19 21:24:17 +00:00
' remote_items ' , ' progressive ' , ' dungeon_counters ' , ' glitch_boots ' , ' killable_thieves ' ,
2021-01-02 11:49:43 +00:00
' tile_shuffle ' , ' bush_shuffle ' , ' shuffle_prizes ' , ' sprite_pool ' , ' dark_room_logic ' ,
' restrict_dungeon_item_on_boss ' ,
2020-10-24 00:46:18 +00:00
' hud_palettes ' , ' sword_palettes ' , ' shield_palettes ' , ' link_palettes ' ] :
2019-12-16 11:52:30 +00:00
value = getattr ( defaults , name ) if getattr ( playerargs , name ) is None else getattr ( playerargs , name )
if player == 1 :
setattr ( ret , name , { 1 : value } )
else :
getattr ( ret , name ) [ player ] = value
return ret
2019-12-15 17:10:01 +00:00
def start ( ) :
args = parse_arguments ( None )
2017-07-14 12:34:33 +00:00
2017-12-17 05:25:46 +00:00
if is_bundled ( ) and len ( sys . argv ) == 1 :
2017-11-28 14:36:32 +00:00
# for the bundled builds, if we have no arguments, the user
# probably wants the gui. Users of the bundled build who want the command line
2017-11-16 03:06:53 +00:00
# interface shouuld specify at least one option, possibly setting a value to a
# default if they like all the defaults
2019-07-11 21:33:27 +00:00
from Gui import guiMain
2017-12-02 14:21:04 +00:00
close_console ( )
2017-11-16 03:06:53 +00:00
guiMain ( )
sys . exit ( 0 )
2017-07-14 12:34:33 +00:00
# ToDo: Validate files further than mere existance
2020-06-09 19:52:46 +00:00
if not os . path . isfile ( args . rom ) :
input (
' Could not find valid base rom for patching at expected path %s . Please run with -h to see help for further information. \n Press Enter to exit. ' % args . rom )
sys . exit ( 1 )
2020-10-24 03:33:52 +00:00
if any ( [ sprite is not None and not os . path . isfile ( sprite ) and not Sprite . get_sprite_from_name ( sprite ) for sprite in
2020-06-09 19:52:46 +00:00
args . sprite . values ( ) ] ) :
input ( ' Could not find link sprite sheet at given location. \n Press Enter to exit. ' )
2017-11-19 21:00:26 +00:00
sys . exit ( 1 )
2017-07-14 12:34:33 +00:00
# set up logger
loglevel = { ' error ' : logging . ERROR , ' info ' : logging . INFO , ' warning ' : logging . WARNING , ' debug ' : logging . DEBUG } [ args . loglevel ]
logging . basicConfig ( format = ' %(message)s ' , level = loglevel )
if args . gui :
2019-07-11 21:33:27 +00:00
from Gui import guiMain
2017-07-14 12:34:33 +00:00
guiMain ( args )
elif args . count is not None :
seed = args . seed
2017-12-17 05:25:46 +00:00
for _ in range ( args . count ) :
2017-07-14 12:34:33 +00:00
main ( seed = seed , args = args )
2020-06-27 22:24:45 +00:00
seed = get_seed ( )
2017-07-14 12:34:33 +00:00
else :
main ( seed = args . seed , args = args )
2017-12-17 05:25:46 +00:00
if __name__ == ' __main__ ' :
start ( )