TFH Futures
This commit is contained in:
@@ -128,6 +128,7 @@ class World(object):
|
||||
set_player_attr('open_pyramid', False)
|
||||
set_player_attr('treasure_hunt_icon', 'Triforce Piece')
|
||||
set_player_attr('treasure_hunt_count', 0)
|
||||
set_player_attr('treasure_hunt_total', 0)
|
||||
set_player_attr('potshuffle', False)
|
||||
set_player_attr('pot_contents', None)
|
||||
|
||||
@@ -1377,11 +1378,6 @@ class Door(object):
|
||||
else:
|
||||
self.passage = False
|
||||
|
||||
def kind(self, world):
|
||||
if self.roomIndex != -1 and self.doorListPos != -1:
|
||||
return world.get_room(self.roomIndex, self.player).kind(self)
|
||||
return None
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, self.__class__) and self.name == other.name
|
||||
|
||||
|
||||
106
CLI.py
106
CLI.py
@@ -6,6 +6,7 @@ import textwrap
|
||||
import shlex
|
||||
import sys
|
||||
|
||||
import source.classes.constants as CONST
|
||||
from source.classes.BabelFish import BabelFish
|
||||
|
||||
from Utils import update_deprecated_args
|
||||
@@ -16,7 +17,6 @@ class ArgumentDefaultsHelpFormatter(argparse.RawTextHelpFormatter):
|
||||
def _get_help_string(self, action):
|
||||
return textwrap.dedent(action.help)
|
||||
|
||||
|
||||
def parse_cli(argv, no_defaults=False):
|
||||
def defval(value):
|
||||
return value if not no_defaults else None
|
||||
@@ -28,49 +28,44 @@ def parse_cli(argv, no_defaults=False):
|
||||
fish = BabelFish(lang=lang)
|
||||
|
||||
# we need to know how many players we have first
|
||||
# also if we're loading our own settings file, we should do that now
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
parser.add_argument('--settingsfile', help="input json file of settings", type=str)
|
||||
parser.add_argument('--multi', default=defval(settings["multi"]), type=lambda value: min(max(int(value), 1), 255))
|
||||
multiargs, _ = parser.parse_known_args(argv)
|
||||
|
||||
if multiargs.settingsfile:
|
||||
settings = apply_settings_file(settings, multiargs.settingsfile)
|
||||
|
||||
parser = argparse.ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
|
||||
|
||||
# get args
|
||||
args = []
|
||||
with open(os.path.join("resources", "app", "cli", "args.json")) as argsFile:
|
||||
args = json.load(argsFile)
|
||||
for arg in args:
|
||||
argdata = args[arg]
|
||||
argname = "--" + arg
|
||||
argatts = {}
|
||||
argatts["help"] = "(default: %(default)s)"
|
||||
if "action" in argdata:
|
||||
argatts["action"] = argdata["action"]
|
||||
if "choices" in argdata:
|
||||
argatts["choices"] = argdata["choices"]
|
||||
argatts["const"] = argdata["choices"][0]
|
||||
argatts["default"] = argdata["choices"][0]
|
||||
argatts["nargs"] = "?"
|
||||
if arg in settings:
|
||||
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)
|
||||
if "help" in argdata and argdata["help"] == "suppress":
|
||||
argatts["help"] = argparse.SUPPRESS
|
||||
elif not isinstance(arghelp, str):
|
||||
argatts["help"] = '\n'.join(arghelp).replace("\\'", "'")
|
||||
else:
|
||||
argatts["help"] = arghelp + " " + argatts["help"]
|
||||
parser.add_argument(argname, **argatts)
|
||||
with open(os.path.join("resources","app","cli","args.json")) as argsFile:
|
||||
args = json.load(argsFile)
|
||||
for arg in args:
|
||||
argdata = args[arg]
|
||||
argname = "--" + arg
|
||||
argatts = {}
|
||||
argatts["help"] = "(default: %(default)s)"
|
||||
if "action" in argdata:
|
||||
argatts["action"] = argdata["action"]
|
||||
if "choices" in argdata:
|
||||
argatts["choices"] = argdata["choices"]
|
||||
argatts["const"] = argdata["choices"][0]
|
||||
argatts["default"] = argdata["choices"][0]
|
||||
argatts["nargs"] = "?"
|
||||
if arg in settings:
|
||||
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)
|
||||
if "help" in argdata and argdata["help"] == "suppress":
|
||||
argatts["help"] = argparse.SUPPRESS
|
||||
elif not isinstance(arghelp,str):
|
||||
argatts["help"] = '\n'.join(arghelp).replace("\\'","'")
|
||||
else:
|
||||
argatts["help"] = arghelp + " " + argatts["help"]
|
||||
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('--count', default=defval(int(settings["count"]) if settings["count"] != "" and settings["count"] is not None else 1), help="\n".join(fish.translate("cli", "help", "count")), 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)
|
||||
parser.add_argument('--count', default=defval(int(settings["count"]) if settings["count"] != "" and settings["count"] is not None else 1), help="\n".join(fish.translate("cli","help","count")), type=int)
|
||||
parser.add_argument('--customitemarray', default={}, help=argparse.SUPPRESS)
|
||||
|
||||
# included for backwards compatibility
|
||||
@@ -78,7 +73,6 @@ def parse_cli(argv, no_defaults=False):
|
||||
parser.add_argument('--multi', default=defval(settings["multi"]), type=lambda value: min(max(int(value), 1), 255))
|
||||
parser.add_argument('--securerandom', default=defval(settings["securerandom"]), action='store_true')
|
||||
parser.add_argument('--teams', default=defval(1), type=lambda value: max(int(value), 1))
|
||||
parser.add_argument('--settingsfile', dest="filename", help="input json file of settings", type=str)
|
||||
|
||||
if multiargs.multi:
|
||||
for player in range(1, multiargs.multi + 1):
|
||||
@@ -92,11 +86,13 @@ def parse_cli(argv, no_defaults=False):
|
||||
if multiargs.multi:
|
||||
defaults = copy.deepcopy(ret)
|
||||
for player in range(1, multiargs.multi + 1):
|
||||
playerargs = parse_cli(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',
|
||||
'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid',
|
||||
'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory',
|
||||
'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max',
|
||||
'triforce_min_difference', 'triforce_goal', 'triforce_pool',
|
||||
'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters',
|
||||
'shufflebosses', 'shuffleenemies', 'enemy_health', 'enemy_damage', 'shufflepots',
|
||||
'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor', 'heartbeep',
|
||||
@@ -110,15 +106,6 @@ def parse_cli(argv, no_defaults=False):
|
||||
return ret
|
||||
|
||||
|
||||
def apply_settings_file(settings, settings_path):
|
||||
if os.path.exists(settings_path):
|
||||
with open(settings_path) as json_file:
|
||||
data = json.load(json_file)
|
||||
for k, v in data.items():
|
||||
settings[k] = v
|
||||
return settings
|
||||
|
||||
|
||||
def parse_settings():
|
||||
# set default settings
|
||||
settings = {
|
||||
@@ -163,6 +150,15 @@ def parse_settings():
|
||||
"mixed_travel": "prevent",
|
||||
"standardize_palettes": "standardize",
|
||||
|
||||
"triforce_pool": 0,
|
||||
"triforce_goal": 0,
|
||||
"triforce_pool_min": 0,
|
||||
"triforce_pool_max": 0,
|
||||
"triforce_goal_min": 0,
|
||||
"triforce_goal_max": 0,
|
||||
"triforce_min_difference": 0,
|
||||
|
||||
|
||||
"code": "",
|
||||
"multi": 1,
|
||||
"names": "",
|
||||
@@ -175,7 +171,7 @@ def parse_settings():
|
||||
"quickswap": False,
|
||||
"heartcolor": "red",
|
||||
"heartbeep": "normal",
|
||||
"sprite": os.path.join(".", "data", "sprites", "official", "001.link.1.zspr"),
|
||||
"sprite": os.path.join(".","data","sprites","official","001.link.1.zspr"),
|
||||
"fastmenu": "normal",
|
||||
"ow_palettes": "default",
|
||||
"uw_palettes": "default",
|
||||
@@ -281,15 +277,17 @@ def parse_settings():
|
||||
|
||||
# read saved settings file if it exists and set these
|
||||
settings_path = os.path.join(".", "resources", "user", "settings.json")
|
||||
settings = apply_settings_file(settings, settings_path)
|
||||
if os.path.exists(settings_path):
|
||||
with(open(settings_path)) as json_file:
|
||||
data = json.load(json_file)
|
||||
for k, v in data.items():
|
||||
settings[k] = v
|
||||
return settings
|
||||
|
||||
# Priority fallback is:
|
||||
# 1: CLI
|
||||
# 2: Settings file(s)
|
||||
# 2: Settings file
|
||||
# 3: Canned defaults
|
||||
|
||||
|
||||
def get_args_priority(settings_args, gui_args, cli_args):
|
||||
args = {}
|
||||
args["settings"] = parse_settings() if settings_args is None else settings_args
|
||||
@@ -316,7 +314,7 @@ def get_args_priority(settings_args, gui_args, cli_args):
|
||||
for k in vars(args["cli"]):
|
||||
load_doesnt_have_key = k not in args["load"]
|
||||
cli_val = cli[k]
|
||||
if isinstance(cli_val, dict) and 1 in cli_val:
|
||||
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
|
||||
@@ -325,9 +323,9 @@ def get_args_priority(settings_args, gui_args, cli_args):
|
||||
args["load"][k] = cli_val
|
||||
|
||||
newArgs = {}
|
||||
for key in ["settings", "gui", "cli", "load"]:
|
||||
for key in [ "settings", "gui", "cli", "load" ]:
|
||||
if args[key]:
|
||||
if isinstance(args[key], dict):
|
||||
if isinstance(args[key],dict):
|
||||
newArgs[key] = argparse.Namespace(**args[key])
|
||||
else:
|
||||
newArgs[key] = args[key]
|
||||
|
||||
31
ItemList.py
31
ItemList.py
@@ -37,7 +37,7 @@ Difficulty = namedtuple('Difficulty',
|
||||
['baseitems', 'bottles', 'bottle_count', 'same_bottle', 'progressiveshield',
|
||||
'basicshield', 'progressivearmor', 'basicarmor', 'swordless',
|
||||
'progressivesword', 'basicsword', 'basicbow', 'timedohko', 'timedother',
|
||||
'triforcehunt', 'triforce_pieces_required', 'retro',
|
||||
'retro',
|
||||
'extras', 'progressive_sword_limit', 'progressive_shield_limit',
|
||||
'progressive_armor_limit', 'progressive_bottle_limit',
|
||||
'progressive_bow_limit', 'heart_piece_limit', 'boss_heart_container_limit'])
|
||||
@@ -60,8 +60,6 @@ difficulties = {
|
||||
basicbow = ['Bow', 'Silver Arrows'],
|
||||
timedohko = ['Green Clock'] * 25,
|
||||
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
|
||||
triforcehunt = ['Triforce Piece'] * 30,
|
||||
triforce_pieces_required = 20,
|
||||
retro = ['Small Key (Universal)'] * 18 + ['Rupees (20)'] * 10,
|
||||
extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra],
|
||||
progressive_sword_limit = 4,
|
||||
@@ -87,8 +85,6 @@ difficulties = {
|
||||
basicbow = ['Bow'] * 2,
|
||||
timedohko = ['Green Clock'] * 25,
|
||||
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
|
||||
triforcehunt = ['Triforce Piece'] * 30,
|
||||
triforce_pieces_required = 20,
|
||||
retro = ['Small Key (Universal)'] * 13 + ['Rupees (5)'] * 15,
|
||||
extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra],
|
||||
progressive_sword_limit = 3,
|
||||
@@ -114,8 +110,6 @@ difficulties = {
|
||||
basicbow = ['Bow'] * 2,
|
||||
timedohko = ['Green Clock'] * 20 + ['Red Clock'] * 5,
|
||||
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
|
||||
triforcehunt = ['Triforce Piece'] * 30,
|
||||
triforce_pieces_required = 20,
|
||||
retro = ['Small Key (Universal)'] * 13 + ['Rupees (5)'] * 15,
|
||||
extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra],
|
||||
progressive_sword_limit = 2,
|
||||
@@ -262,7 +256,7 @@ def generate_itempool(world, player):
|
||||
(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[player]["rupoorcost"], 9999)
|
||||
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, lamps_needed_for_dark_rooms) = get_pool_core(world.progressive, world.shuffle[player], world.difficulty[player], world.treasure_hunt_total[player], world.timer, world.goal[player], world.mode[player], world.swords[player], world.retro[player], world.doorShuffle[player])
|
||||
|
||||
if player in world.pool_adjustment.keys():
|
||||
amt = world.pool_adjustment[player]
|
||||
@@ -320,10 +314,10 @@ def generate_itempool(world, player):
|
||||
if clock_mode is not None:
|
||||
world.clock_mode = clock_mode
|
||||
|
||||
if treasure_hunt_count is not None:
|
||||
world.treasure_hunt_count[player] = treasure_hunt_count
|
||||
if treasure_hunt_icon is not None:
|
||||
world.treasure_hunt_icon[player] = treasure_hunt_icon
|
||||
if world.goal[player] == 'triforcehunt':
|
||||
world.treasure_hunt_icon[player] = 'Triforce Piece'
|
||||
if world.custom:
|
||||
world.treasure_hunt_count[player] = treasure_hunt_count
|
||||
|
||||
world.itempool.extend([item for item in get_dungeon_item_pool(world) if item.player == player
|
||||
and ((item.smallkey and world.keyshuffle[player])
|
||||
@@ -640,13 +634,12 @@ shop_transfer = {'Red Potion': 'Rupees (100)', 'Bee': 'Rupees (5)', 'Blue Potion
|
||||
}
|
||||
|
||||
|
||||
def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, door_shuffle):
|
||||
def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, goal, mode, swords, retro, door_shuffle):
|
||||
pool = []
|
||||
placed_items = {}
|
||||
precollected_items = []
|
||||
clock_mode = None
|
||||
treasure_hunt_count = None
|
||||
treasure_hunt_icon = None
|
||||
triforcepool = ['Triforce Piece'] * treasure_hunt_total
|
||||
|
||||
pool.extend(alwaysitems)
|
||||
|
||||
@@ -740,10 +733,8 @@ def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, r
|
||||
extraitems -= len(diff.timedohko)
|
||||
clock_mode = 'countdown-ohko'
|
||||
if goal == 'triforcehunt':
|
||||
pool.extend(diff.triforcehunt)
|
||||
extraitems -= len(diff.triforcehunt)
|
||||
treasure_hunt_count = diff.triforce_pieces_required
|
||||
treasure_hunt_icon = 'Triforce Piece'
|
||||
pool.extend(triforcepool)
|
||||
extraitems -= len(triforcepool)
|
||||
|
||||
for extra in diff.extras:
|
||||
if extraitems > 0:
|
||||
@@ -771,7 +762,7 @@ def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, r
|
||||
pool.extend(['Small Key (Universal)'])
|
||||
else:
|
||||
pool.extend(['Small Key (Universal)'])
|
||||
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, lamps_needed_for_dark_rooms)
|
||||
|
||||
def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, customitemarray):
|
||||
if isinstance(customitemarray,dict) and 1 in customitemarray:
|
||||
|
||||
9
Main.py
9
Main.py
@@ -22,11 +22,11 @@ from RoomData import create_rooms
|
||||
from Rules import set_rules
|
||||
from Dungeons import create_dungeons, fill_dungeons, fill_dungeons_restrictive
|
||||
from Fill import distribute_items_cutoff, distribute_items_staleness, distribute_items_restrictive, flood_items
|
||||
from Fill import sell_potions, sell_keys, balance_multiworld_progression, balance_money_progression, lock_shop_locations
|
||||
from Fill import sell_potions, sell_keys, balance_multiworld_progression, balance_money_progression
|
||||
from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops
|
||||
from Utils import output_path, parse_player_names
|
||||
|
||||
__version__ = '0.3.1.5-u'
|
||||
__version__ = '0.3.1.4-u'
|
||||
|
||||
|
||||
class EnemizerError(RuntimeError):
|
||||
@@ -86,6 +86,8 @@ def main(args, seed=None, fish=None):
|
||||
world.keydropshuffle = args.keydropshuffle.copy()
|
||||
world.mixed_travel = args.mixed_travel.copy()
|
||||
world.standardize_palettes = args.standardize_palettes.copy()
|
||||
world.treasure_hunt_count = args.triforce_goal.copy()
|
||||
world.treasure_hunt_total = args.triforce_pool.copy()
|
||||
|
||||
world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)}
|
||||
|
||||
@@ -165,9 +167,6 @@ def main(args, seed=None, fish=None):
|
||||
sell_potions(world, player)
|
||||
if world.retro[player]:
|
||||
sell_keys(world, player)
|
||||
else:
|
||||
lock_shop_locations(world, player)
|
||||
|
||||
|
||||
logger.info(world.fish.translate("cli","cli","placing.dungeon.prizes"))
|
||||
|
||||
|
||||
@@ -171,9 +171,11 @@ def roll_settings(weights):
|
||||
ret.openpyramid = goal == 'fast_ganon' if ret.shuffle in ['vanilla', 'dungeonsfull', 'dungeonssimple'] else False
|
||||
|
||||
ret.crystals_gt = get_choice('tower_open')
|
||||
|
||||
ret.crystals_ganon = get_choice('ganon_open')
|
||||
|
||||
if ret.goal == 'triforcehunt':
|
||||
ret.triforce_goal = random.randint(int(get_choice('triforce_goal_min')),int(get_choice('triforce_goal_max')))
|
||||
ret.triforce_pool = random.randint(max(int(get_choice('triforce_pool_min')),ret.triforce_goal + int(get_choice('triforce_min_difference'))),int(get_choice('triforce_pool_max')))
|
||||
ret.mode = get_choice('world_state')
|
||||
if ret.mode == 'retro':
|
||||
ret.mode = 'open'
|
||||
@@ -214,6 +216,7 @@ def roll_settings(weights):
|
||||
|
||||
ret.beemizer = int(get_choice('beemizer')) if 'beemizer' in weights else 0
|
||||
|
||||
|
||||
inventoryweights = weights.get('startinventory', {})
|
||||
startitems = []
|
||||
for item in inventoryweights.keys():
|
||||
|
||||
7
Rom.py
7
Rom.py
@@ -16,7 +16,7 @@ from BaseClasses import CollectionState, ShopType, Region, Location, Door, DoorT
|
||||
from DoorShuffle import compass_data, DROptions, boss_indicator
|
||||
from Dungeons import dungeon_music_addresses
|
||||
from KeyDoorShuffle import count_locations_exclude_logic
|
||||
from Regions import location_table, shop_to_location_table
|
||||
from Regions import location_table
|
||||
from RoomData import DoorKind
|
||||
from Text import MultiByteTextMapper, CompressedTextMapper, text_addresses, Credits, TextTable
|
||||
from Text import Uncle_texts, Ganon1_texts, TavernMan_texts, Sahasrahla2_texts, Triforce_texts, Blind_texts, BombShop2_texts, junk_texts
|
||||
@@ -1568,10 +1568,7 @@ def write_custom_shops(rom, world, player):
|
||||
break
|
||||
if world.shopsanity[player] or shop.type == ShopType.TakeAny:
|
||||
rom.write_byte(0x186560 + shop.sram_address + index, 1)
|
||||
loc_item = world.get_location(shop_to_location_table[shop.region.name][index], player).item
|
||||
if not loc_item:
|
||||
loc_item = ItemFactory(item['item'], player)
|
||||
item_id = loc_item.code
|
||||
item_id = ItemFactory(item['item'], player).code
|
||||
price = int16_as_bytes(item['price'])
|
||||
replace = ItemFactory(item['replacement'], player).code if item['replacement'] else 0xFF
|
||||
replace_price = int16_as_bytes(item['replacement_price'])
|
||||
|
||||
Reference in New Issue
Block a user