From 389606619398007b326d813b535ec94738aa75ab Mon Sep 17 00:00:00 2001 From: Kara Alexandra Date: Tue, 29 Jun 2021 10:36:53 -0700 Subject: [PATCH 01/30] Reimplement --securerandom Seeds should be reproducable without the flag passed, and unreproducable with the flag passed. With --securerandom, generate a 9-char alphanumeric string to use to make filenames differ. --- Bosses.py | 2 +- DoorShuffle.py | 2 +- DungeonGenerator.py | 2 +- DungeonRandomizer.py | 2 +- Dungeons.py | 2 +- EntranceShuffle.py | 2 +- Fill.py | 2 +- ItemList.py | 2 +- Main.py | 11 ++++++----- Mystery.py | 2 +- Plando.py | 2 +- PotShuffle.py | 2 +- Rom.py | 5 +++-- resources/app/cli/lang/de.json | 2 +- resources/app/cli/lang/en.json | 2 +- resources/app/cli/lang/es.json | 2 +- 16 files changed, 23 insertions(+), 21 deletions(-) diff --git a/Bosses.py b/Bosses.py index ebf8b4dd..253717bd 100644 --- a/Bosses.py +++ b/Bosses.py @@ -1,5 +1,5 @@ import logging -import random +import RaceRandom as random from BaseClasses import Boss from Fill import FillError diff --git a/DoorShuffle.py b/DoorShuffle.py index ee38f00c..acb0dee8 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -1,4 +1,4 @@ -import random +import RaceRandom as random from collections import defaultdict, deque import logging import operator as op diff --git a/DungeonGenerator.py b/DungeonGenerator.py index c8599748..1c49cba0 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -1,4 +1,4 @@ -import random +import RaceRandom as random import collections import itertools from collections import defaultdict, deque diff --git a/DungeonRandomizer.py b/DungeonRandomizer.py index b1c02c81..d24e81d6 100755 --- a/DungeonRandomizer.py +++ b/DungeonRandomizer.py @@ -3,7 +3,7 @@ import argparse import copy import os import logging -import random +import RaceRandom as random import textwrap import shlex import sys diff --git a/Dungeons.py b/Dungeons.py index d5297400..596da920 100644 --- a/Dungeons.py +++ b/Dungeons.py @@ -1,4 +1,4 @@ -import random +import RaceRandom as random from BaseClasses import Dungeon from Bosses import BossFactory diff --git a/EntranceShuffle.py b/EntranceShuffle.py index e78b35b8..c1af7956 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -1,4 +1,4 @@ -import random +import RaceRandom as random # ToDo: With shuffle_ganon option, prevent gtower from linking to an exit only location through a 2 entrance cave. from collections import defaultdict diff --git a/Fill.py b/Fill.py index c1488113..48f020c3 100644 --- a/Fill.py +++ b/Fill.py @@ -1,4 +1,4 @@ -import random +import RaceRandom as random import logging from BaseClasses import CollectionState diff --git a/ItemList.py b/ItemList.py index 62648862..a16219f4 100644 --- a/ItemList.py +++ b/ItemList.py @@ -1,7 +1,7 @@ from collections import namedtuple import logging import math -import random +import RaceRandom as random from BaseClasses import Region, RegionType, Shop, ShopType, Location, CollectionState from Bosses import place_bosses diff --git a/Main.py b/Main.py index fb44aa7c..072d12dd 100644 --- a/Main.py +++ b/Main.py @@ -4,7 +4,8 @@ from itertools import zip_longest import json import logging import os -import random +import RaceRandom as random +import string import time import zlib @@ -41,8 +42,8 @@ def main(args, seed=None, fish=None): start = time.perf_counter() - # if args.securerandom: - # random.use_secure() + if args.securerandom: + random.use_secure() # initialize the world if args.code: @@ -61,7 +62,7 @@ def main(args, seed=None, fish=None): random.seed(world.seed) if args.securerandom: - world.seed = None + world.seed = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(9)) world.remote_items = args.remote_items.copy() world.mapshuffle = args.mapshuffle.copy() @@ -332,7 +333,7 @@ def main(args, seed=None, fish=None): 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","used.enemizer") % (YES if enemized else NO)) - logger.info(world.fish.translate("cli","cli","seed") + ": %d", world.seed) + logger.info(world.fish.translate("cli","cli","seed") + ": %s", world.seed) logger.info(world.fish.translate("cli","cli","total.time"), time.perf_counter() - start) # print_wiki_doors_by_room(dungeon_regions,world,1) diff --git a/Mystery.py b/Mystery.py index 6d0189f0..0b913455 100644 --- a/Mystery.py +++ b/Mystery.py @@ -1,6 +1,6 @@ import argparse import logging -import random +import RaceRandom as random import urllib.request import urllib.parse import yaml diff --git a/Plando.py b/Plando.py index 5b66876e..c32c75cd 100755 --- a/Plando.py +++ b/Plando.py @@ -3,7 +3,7 @@ import argparse import hashlib import logging import os -import random +import RaceRandom as random import time import sys diff --git a/PotShuffle.py b/PotShuffle.py index e8e6d3ce..d62f52eb 100644 --- a/PotShuffle.py +++ b/PotShuffle.py @@ -275,7 +275,7 @@ vanilla_pots = { def shuffle_pots(world, player): - import random + import RaceRandom as random new_pot_contents = {} diff --git a/Rom.py b/Rom.py index 5c2fae02..084a456a 100644 --- a/Rom.py +++ b/Rom.py @@ -5,7 +5,7 @@ import json import hashlib import logging import os -import random +import RaceRandom as random import struct import sys import subprocess @@ -1542,8 +1542,9 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): # set rom name # 21 bytes from Main import __version__ + seedstring = f'{world.seed:09}' if isinstance(world.seed, int) else world.seed # todo: change to DR when Enemizer is okay with DR - rom.name = bytearray(f'ER{__version__.split("-")[0].replace(".","")[0:3]}_{team+1}_{player}_{world.seed:09}\0', 'utf8')[:21] + rom.name = bytearray(f'ER{__version__.split("-")[0].replace(".","")[0:3]}_{team+1}_{player}_{seedstring}\0', 'utf8')[:21] rom.name.extend([0] * (21 - len(rom.name))) rom.write_bytes(0x7FC0, rom.name) diff --git a/resources/app/cli/lang/de.json b/resources/app/cli/lang/de.json index d2c5d523..6a72d688 100644 --- a/resources/app/cli/lang/de.json +++ b/resources/app/cli/lang/de.json @@ -1,6 +1,6 @@ { "cli": { - "app.title": "ALttP Tür Randomisier Version %s - Nummer: %d, Code: %s", + "app.title": "ALttP Tür Randomisier Version %s - Nummer: %s, Code: %s", "shuffling.world": "Welt wird durchmischt.", "generating.itempool": "Generier Gegenstandsbasis.", "calc.access.rules": "Berechne Zugriffsregeln.", diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index 145667ef..6dc4418d 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -2,7 +2,7 @@ "cli": { "yes": "Yes", "no": "No", - "app.title": "ALttP Door Randomizer Version %s - Seed: %d, Code: %s", + "app.title": "ALttP Door Randomizer Version %s - Seed: %s, Code: %s", "version": "Version", "seed": "Seed", "player": "Player", diff --git a/resources/app/cli/lang/es.json b/resources/app/cli/lang/es.json index def18849..8bff9dd0 100644 --- a/resources/app/cli/lang/es.json +++ b/resources/app/cli/lang/es.json @@ -1,6 +1,6 @@ { "cli": { - "app.title": "ALttP Puerta Aleatorizador Versión %s - Número: %d, Código: %s", + "app.title": "ALttP Puerta Aleatorizador Versión %s - Número: %s, Código: %s", "player": "Jugador", "shuffling.world": "Barajando el Mundo", "shuffling.dungeons": "Barajando Mazmorras", From 6f990aecc180d8c14701ef37ab3e72a644f49bec Mon Sep 17 00:00:00 2001 From: Catobat <69204835+Catobat@users.noreply.github.com> Date: Mon, 12 Jul 2021 01:28:52 +0200 Subject: [PATCH 02/30] More bomb door candidates --- DoorShuffle.py | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index 588c2857..00e787b9 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -1704,25 +1704,14 @@ def smooth_door_pairs(world, player): remove_pair(door, world, player) if type_b == DoorKind.SmallKey: remove_pair(door, world, player) - elif type_a in [DoorKind.Bombable, DoorKind.Dashable] or type_b in [DoorKind.Bombable, DoorKind.Dashable]: + else: if valid_pair: - new_type = type_a - if type_a != type_b: - new_type = DoorKind.Dashable if type_a == DoorKind.Dashable or type_b == DoorKind.Dashable else DoorKind.Bombable - if type_a != new_type: - room_a.change(door.doorListPos, new_type) - if type_b != new_type: - room_b.change(partner.doorListPos, new_type) - add_pair(door, partner, world, player) - spoiler_type = 'Bomb Door' if new_type == DoorKind.Bombable else 'Dash Door' - world.spoiler.set_door_type(door.name + ' <-> ' + partner.name, spoiler_type, player) - counter = bombable_counts if new_type == DoorKind.Bombable else dashable_counts - counter[door.entrance.parent_region.dungeon] += 1 - else: + bd_candidates[door.entrance.parent_region.dungeon].append(door) + elif type_a in [DoorKind.Bombable, DoorKind.Dashable] or type_b in [DoorKind.Bombable, DoorKind.Dashable]: if type_a in [DoorKind.Bombable, DoorKind.Dashable]: room_a.change(door.doorListPos, DoorKind.Normal) remove_pair(door, world, player) - elif type_b in [DoorKind.Bombable, DoorKind.Dashable]: + else: room_b.change(partner.doorListPos, DoorKind.Normal) remove_pair(partner, world, player) elif valid_pair and type_a != DoorKind.SmallKey and type_b != DoorKind.SmallKey: From 0ade4c5795788b811662c377585c8d983723d6a7 Mon Sep 17 00:00:00 2001 From: Catobat <69204835+Catobat@users.noreply.github.com> Date: Mon, 12 Jul 2021 04:21:34 +0200 Subject: [PATCH 03/30] Counters no longer needed --- DoorShuffle.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index 00e787b9..b3f8cb5e 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -1678,7 +1678,7 @@ def change_door_to_small_key(d, world, player): def smooth_door_pairs(world, player): all_doors = [x for x in world.doors if x.player == player] skip = set() - bd_candidates, dashable_counts, bombable_counts = defaultdict(list), defaultdict(int), defaultdict(int) + bd_candidates = defaultdict(list) for door in all_doors: if door.type in [DoorType.Normal, DoorType.Interior] and door not in skip and not door.entranceFlag: partner = door.dest @@ -1716,7 +1716,7 @@ def smooth_door_pairs(world, player): remove_pair(partner, world, player) elif valid_pair and type_a != DoorKind.SmallKey and type_b != DoorKind.SmallKey: bd_candidates[door.entrance.parent_region.dungeon].append(door) - shuffle_bombable_dashable(bd_candidates, bombable_counts, dashable_counts, world, player) + shuffle_bombable_dashable(bd_candidates, world, player) world.paired_doors[player] = [x for x in world.paired_doors[player] if x.pair or x.original] @@ -1753,15 +1753,15 @@ def stateful_door(door, kind): return False -def shuffle_bombable_dashable(bd_candidates, bombable_counts, dashable_counts, world, player): +def shuffle_bombable_dashable(bd_candidates, world, player): if world.doorShuffle[player] == 'basic': for dungeon, candidates in bd_candidates.items(): - diff = bomb_dash_counts[dungeon.name][1] - dashable_counts[dungeon] + diff = bomb_dash_counts[dungeon.name][1] if diff > 0: for chosen in random.sample(candidates, min(diff, len(candidates))): change_pair_type(chosen, DoorKind.Dashable, world, player) candidates.remove(chosen) - diff = bomb_dash_counts[dungeon.name][0] - bombable_counts[dungeon] + diff = bomb_dash_counts[dungeon.name][0] if diff > 0: for chosen in random.sample(candidates, min(diff, len(candidates))): change_pair_type(chosen, DoorKind.Bombable, world, player) @@ -1770,16 +1770,12 @@ def shuffle_bombable_dashable(bd_candidates, bombable_counts, dashable_counts, w remove_pair_type_if_present(excluded, world, player) elif world.doorShuffle[player] == 'crossed': all_candidates = sum(bd_candidates.values(), []) - all_bomb_counts = sum(bombable_counts.values()) - all_dash_counts = sum(dashable_counts.values()) - if all_dash_counts < 8: - for chosen in random.sample(all_candidates, min(8 - all_dash_counts, len(all_candidates))): - change_pair_type(chosen, DoorKind.Dashable, world, player) - all_candidates.remove(chosen) - if all_bomb_counts < 12: - for chosen in random.sample(all_candidates, min(12 - all_bomb_counts, len(all_candidates))): - change_pair_type(chosen, DoorKind.Bombable, world, player) - all_candidates.remove(chosen) + for chosen in random.sample(all_candidates, min(8, len(all_candidates))): + change_pair_type(chosen, DoorKind.Dashable, world, player) + all_candidates.remove(chosen) + for chosen in random.sample(all_candidates, min(12, len(all_candidates))): + change_pair_type(chosen, DoorKind.Bombable, world, player) + all_candidates.remove(chosen) for excluded in all_candidates: remove_pair_type_if_present(excluded, world, player) From b5aae926e71a5687f31d60fac1022d4761ba0010 Mon Sep 17 00:00:00 2001 From: aerinon Date: Tue, 13 Jul 2021 13:19:14 -0700 Subject: [PATCH 04/30] Minor baserom updates --- Main.py | 2 +- RELEASENOTES.md | 3 +++ Rom.py | 2 +- data/base2current.bps | Bin 136227 -> 136227 bytes 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Main.py b/Main.py index 73b60974..eb8380f3 100644 --- a/Main.py +++ b/Main.py @@ -27,7 +27,7 @@ from Fill import sell_potions, sell_keys, balance_multiworld_progression, balanc from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops from Utils import output_path, parse_player_names -__version__ = '0.4.0.10u' +__version__ = '0.4.0.11u' class EnemizerError(RuntimeError): diff --git a/RELEASENOTES.md b/RELEASENOTES.md index d55904b8..cafdb92f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -22,6 +22,9 @@ For accessibility, you now get a C or P indicator to the left of the magic bar o # Bug Fixes and Notes. +* 0.4.0.11 + * Some minor base rom fixes + * Improved distribution of bombable/dashable doors * 0.4.0.10 * Renamed to pseudoboots * Some release note updates diff --git a/Rom.py b/Rom.py index 6c351828..1bdf1a59 100644 --- a/Rom.py +++ b/Rom.py @@ -30,7 +30,7 @@ from EntranceShuffle import door_addresses, exit_ids JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = 'df3386b7a48d79950a1432b8bbaafde1' +RANDOMIZERBASEHASH = '669813697df6a132611f4c7a008ebaae' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 2ef0bf7d96739707083688cc6cdd7ae30569487b..9d4ad8e3765029bdbeb086dd921deed9a10a87d3 100644 GIT binary patch delta 5204 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 From a123661eca76f635324c09f8e6a36c7f85a2c89c Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 15 Jul 2021 10:32:25 -0700 Subject: [PATCH 05/30] Don't fix ugly smalls in vanilla --- DoorShuffle.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index b3f8cb5e..2e6f8b44 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -100,8 +100,8 @@ def link_doors_main(world, player): analyze_portals(world, player) for portal in world.dungeon_portals[player]: connect_portal(portal, world, player) - - fix_big_key_doors_with_ugly_smalls(world, player) + if not world.doorShuffle[player] == 'vanilla': + fix_big_key_doors_with_ugly_smalls(world, player) if world.doorShuffle[player] == 'vanilla': for entrance, ext in open_edges: connect_two_way(world, entrance, ext, player) From 06486e88a2dbc200c99357c4fb0a16dc96d45b93 Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 15 Jul 2021 10:33:04 -0700 Subject: [PATCH 06/30] Cutoff rug addition --- Rom.py | 2 +- asm/doortables.asm | 4 ++-- data/base2current.bps | Bin 136227 -> 136225 bytes 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Rom.py b/Rom.py index 1bdf1a59..5c61e5c2 100644 --- a/Rom.py +++ b/Rom.py @@ -30,7 +30,7 @@ from EntranceShuffle import door_addresses, exit_ids JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '669813697df6a132611f4c7a008ebaae' +RANDOMIZERBASEHASH = '25dd18672e1234c85900f5b2155e7e4f' class JsonRom(object): diff --git a/asm/doortables.asm b/asm/doortables.asm index db1b6711..8ee0dd60 100644 --- a/asm/doortables.asm +++ b/asm/doortables.asm @@ -580,8 +580,8 @@ dw $00bc, $00a2, $00a3, $00c2, $001a, $0049, $0014, $008c ; Ice Many Pots, Swamp Waterfall, GT Gauntlet 3, Eastern Push Block, Eastern Courtyard, Eastern Map Valley ; Eastern Cannonball, HC East Hall dw $009f, $0066, $005d, $00a8, $00a9, $00aa, $00b9, $0052 -; HC West Hall, TR Dash Bridge, TR Hub, Pod Arena, GT Petting Zoo -dw $0050, $00c5, $00c6, $0009, $0003, $002a, $007d +; HC West Hall, TR Dash Bridge, TR Hub, Pod Arena, GT Petting Zoo, Ice Spike Cross +dw $0050, $00c5, $00c6, $0009, $0003, $002a, $007d, $005e dw $ffff ; dungeon tables diff --git a/data/base2current.bps b/data/base2current.bps index 9d4ad8e3765029bdbeb086dd921deed9a10a87d3..53bd7d8680aa4516815cb90e352fe3ea90cbc137 100644 GIT binary patch delta 53 zcmV-50LuTPs0g8`2(Ur{1l?dFpR+~*;rj@Z2Bx L+12*e5Zv);rj|NhAI=48}|`Ufs-%&A_8ANgH!#tQ~d$P N76@kAM>B8q$^myo7aITo From 68dc27902b46bbc7998490bf002287bdb667225f Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 15 Jul 2021 16:02:07 -0700 Subject: [PATCH 07/30] SFX Shuffle initial implementation --- Adjuster.py | 1 + AdjusterMain.py | 2 +- CLI.py | 3 +- Main.py | 3 +- Mystery.py | 1 + Rom.py | 7 +- mystery_example.yml | 3 + resources/app/cli/args.json | 4 + resources/app/cli/lang/en.json | 1 + .../app/gui/adjust/overview/widgets.json | 3 +- resources/app/gui/lang/en.json | 2 + .../gui/randomize/gameoptions/widgets.json | 3 +- source/classes/SFX.py | 191 ++++++++++++++++++ source/classes/constants.py | 3 +- source/gui/adjust/overview.py | 1 + 15 files changed, 221 insertions(+), 7 deletions(-) create mode 100644 source/classes/SFX.py diff --git a/Adjuster.py b/Adjuster.py index c6f42e6e..a6e964a8 100755 --- a/Adjuster.py +++ b/Adjuster.py @@ -36,6 +36,7 @@ def main(): parser.add_argument('--ow_palettes', default='default', choices=['default', 'random', 'blackout']) parser.add_argument('--uw_palettes', default='default', choices=['default', 'random', 'blackout']) parser.add_argument('--reduce_flashing', help='Reduce some in-game flashing.', action='store_true') + parser.add_argument('--shuffle_sfx', help='Shuffles sound sfx', action='store_true') parser.add_argument('--sprite', help='''\ Path to a sprite sheet to use for Link. Needs to be in binary format and have a length of 0x7000 (28672) bytes, diff --git a/AdjusterMain.py b/AdjusterMain.py index bc463444..7d7e2f6e 100644 --- a/AdjusterMain.py +++ b/AdjusterMain.py @@ -25,7 +25,7 @@ def adjust(args): args.sprite = None apply_rom_settings(rom, args.heartbeep, args.heartcolor, args.quickswap, args.fastmenu, args.disablemusic, - args.sprite, args.ow_palettes, args.uw_palettes, args.reduce_flashing) + args.sprite, args.ow_palettes, args.uw_palettes, args.reduce_flashing, args.shuffle_sfx) output_path.cached_path = args.outputpath rom.write_to_file(output_path('%s.sfc' % outfilebase)) diff --git a/CLI.py b/CLI.py index d87e1e2c..dc374769 100644 --- a/CLI.py +++ b/CLI.py @@ -102,7 +102,7 @@ def parse_cli(argv, no_defaults=False): 'shufflebosses', 'shuffleenemies', 'enemy_health', 'enemy_damage', 'shufflepots', 'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor', 'heartbeep', 'remote_items', 'shopsanity', 'keydropshuffle', 'mixed_travel', 'standardize_palettes', 'code', - 'reduce_flashing']: + 'reduce_flashing', 'shuffle_sfx']: value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name) if player == 1: setattr(ret, name, {1: value}) @@ -190,6 +190,7 @@ def parse_settings(): "ow_palettes": "default", "uw_palettes": "default", "reduce_flashing": False, + "shuffle_sfx": False, # Spoiler defaults to TRUE # Playthrough defaults to TRUE diff --git a/Main.py b/Main.py index eb8380f3..71ef017a 100644 --- a/Main.py +++ b/Main.py @@ -281,7 +281,8 @@ def main(args, seed=None, fish=None): apply_rom_settings(rom, args.heartbeep[player], args.heartcolor[player], args.quickswap[player], args.fastmenu[player], args.disablemusic[player], args.sprite[player], - args.ow_palettes[player], args.uw_palettes[player], args.reduce_flashing[player]) + args.ow_palettes[player], args.uw_palettes[player], args.reduce_flashing[player], + args.shuffle_sfx[player]) if args.jsonout: jsonout[f'patch_t{team}_p{player}'] = rom.patches diff --git a/Mystery.py b/Mystery.py index f82e64d2..8914c1be 100644 --- a/Mystery.py +++ b/Mystery.py @@ -231,6 +231,7 @@ def roll_settings(weights): ret.heartbeep = get_choice('heartbeep', romweights) ret.ow_palettes = get_choice('ow_palettes', romweights) ret.uw_palettes = get_choice('uw_palettes', romweights) + ret.uw_palettes = get_choice('shuffle_sfx', romweights) == 'on' return ret diff --git a/Rom.py b/Rom.py index 5c61e5c2..0e2215a7 100644 --- a/Rom.py +++ b/Rom.py @@ -28,6 +28,8 @@ from Utils import output_path, local_path, int16_as_bytes, int32_as_bytes, snes_ from Items import ItemFactory from EntranceShuffle import door_addresses, exit_ids +from source.classes.SFX import randomize_sfx + JAP10HASH = '03a63945398191337e896e5771f77173' RANDOMIZERBASEHASH = '25dd18672e1234c85900f5b2155e7e4f' @@ -1624,7 +1626,7 @@ def hud_format_text(text): def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, sprite, - ow_palettes, uw_palettes, reduce_flashing): + ow_palettes, uw_palettes, reduce_flashing, shuffle_sfx): if not os.path.exists("data/sprites/official/001.link.1.zspr") and rom.orig_buffer: dump_zspr(rom.orig_buffer[0x80000:0x87000], rom.orig_buffer[0xdd308:0xdd380], @@ -1727,6 +1729,9 @@ def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, spr elif uw_palettes == 'blackout': blackout_uw_palettes(rom) + if shuffle_sfx: + randomize_sfx(rom) + if isinstance(rom, LocalRom): rom.write_crc() diff --git a/mystery_example.yml b/mystery_example.yml index e349063d..028e7110 100644 --- a/mystery_example.yml +++ b/mystery_example.yml @@ -132,3 +132,6 @@ half: 0 quarter: 1 off: 0 + shuffle_sfx: + on: 1 + off: 1 diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index 47bb3987..dc4b917c 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -199,6 +199,10 @@ "action": "store_true", "type": "bool" }, + "shuffle_sfx": { + "action": "store_true", + "type": "bool" + }, "mapshuffle": { "action": "store_true", "type": "bool" diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index 0ff910a9..8c5c0f8c 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -295,6 +295,7 @@ "sprite that will be extracted." ], "reduce_flashing": [ "Reduce some in-game flashing (default: %(default)s)" ], + "shuffle_sfx": [ "Shuffle sounds effects (default: %(default)s)" ], "create_rom": [ "Create an output rom file. (default: %(default)s)" ], "gui": [ "Launch the GUI. (default: %(default)s)" ], "jsonout": [ diff --git a/resources/app/gui/adjust/overview/widgets.json b/resources/app/gui/adjust/overview/widgets.json index b61fff0e..85efcf1f 100644 --- a/resources/app/gui/adjust/overview/widgets.json +++ b/resources/app/gui/adjust/overview/widgets.json @@ -2,7 +2,8 @@ "checkboxes": { "nobgm": { "type": "checkbox" }, "quickswap": { "type": "checkbox" }, - "reduce_flashing": {"type": "checkbox"} + "reduce_flashing": {"type": "checkbox"}, + "shuffle_sfx": {"type": "checkbox"} }, "leftAdjustFrame": { "heartcolor": { diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index 0d9e3836..24134897 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -3,6 +3,7 @@ "adjust.nobgm": "Disable Music & MSU-1", "adjust.quickswap": "L/R Quickswapping", "adjust.reduce_flashing": "Reduce Flashing", + "adjust.shuffle_sfx": "Shuffle Sound Effects", "adjust.heartcolor": "Heart Color", "adjust.heartcolor.red": "Red", @@ -134,6 +135,7 @@ "randomizer.gameoptions.nobgm": "Disable Music & MSU-1", "randomizer.gameoptions.quickswap": "L/R Quickswapping", "randomizer.gameoptions.reduce_flashing": "Reduce Flashing", + "randomizer.gameoptions.shuffle_sfx": "Shuffle Sound Effects", "randomizer.gameoptions.heartcolor": "Heart Color", "randomizer.gameoptions.heartcolor.red": "Red", diff --git a/resources/app/gui/randomize/gameoptions/widgets.json b/resources/app/gui/randomize/gameoptions/widgets.json index 63556e0f..6efe32c8 100644 --- a/resources/app/gui/randomize/gameoptions/widgets.json +++ b/resources/app/gui/randomize/gameoptions/widgets.json @@ -2,7 +2,8 @@ "checkboxes": { "nobgm": { "type": "checkbox" }, "quickswap": { "type": "checkbox" }, - "reduce_flashing": {"type": "checkbox"} + "reduce_flashing": {"type": "checkbox"}, + "shuffle_sfx": {"type": "checkbox"} }, "leftRomOptionsFrame": { "heartcolor": { diff --git a/source/classes/SFX.py b/source/classes/SFX.py new file mode 100644 index 00000000..ed6d93f6 --- /dev/null +++ b/source/classes/SFX.py @@ -0,0 +1,191 @@ +import random +from Utils import int16_as_bytes + + +class SFX(object): + + def __init__(self, name, sfx_set, orig_id, addr, chain, accomp=False): + self.name = name + self.sfx_set = sfx_set + self.orig_id = orig_id + self.addr = addr + self.chain = chain + self.accomp = accomp + + self.target_set = None + self.target_id = None + self.target_chain = None + + +def init_sfx_data(): + sfx_pool = [SFX('Slash1', 0x02, 0x01, 0x2614, []), SFX('Slash2', 0x02, 0x02, 0x2625, []), + SFX('Slash3', 0x02, 0x03, 0x2634, []), SFX('Slash4', 0x02, 0x04, 0x2643, []), + SFX('Wall clink', 0x02, 0x05, 0x25DD, []), SFX('Bombable door clink', 0x02, 0x06, 0x25D7, []), + SFX('Fwoosh shooting', 0x02, 0x07, 0x25B7, []), SFX('Arrow hitting wall', 0x02, 0x08, 0x25E3, []), + SFX('Boomerang whooshing', 0x02, 0x09, 0x25AD, []), SFX('Hookshot', 0x02, 0x0A, 0x25C7, []), + SFX('Placing bomb', 0x02, 0x0B, 0x2478, []), + SFX('Bomb exploding/Quake/Bombos/Exploding wall', 0x02, 0x0C, 0x269C, []), + SFX('Powder', 0x02, 0x0D, 0x2414, [0x3f]), SFX('Fire rod shot', 0x02, 0x0E, 0x2404, []), + SFX('Ice rod shot', 0x02, 0x0F, 0x24C3, []), SFX('Hammer use', 0x02, 0x10, 0x23FA, []), + SFX('Hammering peg', 0x02, 0x11, 0x23F0, []), SFX('Digging', 0x02, 0x12, 0x23CD, []), + SFX('Flute use', 0x02, 0x13, 0x23A0, [0x3e]), SFX('Cape on', 0x02, 0x14, 0x2380, []), + SFX('Cape off/Wallmaster grab', 0x02, 0x15, 0x2390, []), SFX('Staircase', 0x02, 0x16, 0x232C, []), + SFX('Staircase', 0x02, 0x17, 0x2344, []), SFX('Staircase', 0x02, 0x18, 0x2356, []), + SFX('Staircase', 0x02, 0x19, 0x236E, []), SFX('Tall grass/Hammer hitting bush', 0x02, 0x1A, 0x2316, []), + SFX('Mire shallow water', 0x02, 0x1B, 0x2307, []), SFX('Shallow water', 0x02, 0x1C, 0x2301, []), + SFX('Lifting object', 0x02, 0x1D, 0x22BB, []), SFX('Cutting grass', 0x02, 0x1E, 0x2577, []), + SFX('Item breaking', 0x02, 0x1F, 0x22E9, []), SFX('Item falling in pit', 0x02, 0x20, 0x22DA, []), + SFX('Bomb hitting ground/General bang', 0x02, 0x21, 0x22CF, []), + SFX('Pushing object/Armos bounce', 0x02, 0x22, 0x2107, []), SFX('Boots dust', 0x02, 0x23, 0x22B1, []), + SFX('Splashing', 0x02, 0x24, 0x22A5, [0x3d]), SFX('Mire shallow water again?', 0x02, 0x25, 0x2296, []), + SFX('Link taking damage', 0x02, 0x26, 0x2844, []), SFX('Fainting', 0x02, 0x27, 0x2252, []), + SFX('Item splash', 0x02, 0x28, 0x2287, []), SFX('Rupee refill', 0x02, 0x29, 0x243F, [0x3b]), + SFX('Fire rod shot hitting wall/Bombos spell', 0x02, 0x2A, 0x2033, []), + SFX('Heart beep/Text box', 0x02, 0x2B, 0x1FF2, []), SFX('Sword up', 0x02, 0x2C, 0x1FD9, [0x3a]), + SFX('Magic drain', 0x02, 0x2D, 0x20A6, []), SFX('GT opening', 0x02, 0x2E, 0x1FCA, [0x39]), + SFX('GT opening/Water drain', 0x02, 0x2F, 0x1F47, [0x38]), SFX('Cucco', 0x02, 0x30, 0x1EF1, []), + SFX('Fairy', 0x02, 0x31, 0x20CE, []), SFX('Bug net', 0x02, 0x32, 0x1D47, []), + SFX('Teleport2', 0x02, 0x33, 0x1CDC, [], True), SFX('Teleport1', 0x02, 0x34, 0x1F6F, [0x33]), + SFX('Quake/Vitreous/Zora king/Armos/Pyramid/Lanmo', 0x02, 0x35, 0x1C67, [0x36]), + SFX('Mire entrance (extends above)', 0x02, 0x36, 0x1C64, [], True), + SFX('Spin charged', 0x02, 0x37, 0x1A43, []), SFX('Water sound', 0x02, 0x38, 0x1F6F, [], True), + SFX('GT opening thunder', 0x02, 0x39, 0x1F9C, [], True), SFX('Sword up', 0x02, 0x3A, 0x1FE7, [], True), + SFX('Quiet rupees', 0x02, 0x3B, 0x2462, [], True), SFX('Error beep', 0x02, 0x3C, 0x1A37, []), + SFX('Big splash', 0x02, 0x3D, 0x22AB, [], True), SFX('Flute again', 0x02, 0x3E, 0x23B5, [], True), + SFX('Powder paired', 0x02, 0x3F, 0x2435, [], True), + + SFX('Sword beam', 0x03, 0x01, 0x1A18, []), + SFX('TR opening', 0x03, 0x02, 0x254E, []), SFX('Pyramid hole', 0x03, 0x03, 0x224A, []), + SFX('Angry soldier', 0x03, 0x04, 0x220E, []), SFX('Lynel shot/Javelin toss', 0x03, 0x05, 0x25B7, []), + SFX('BNC swing/Phantom ganon/Helma tail/Arrghus swoosh', 0x03, 0x06, 0x21F5, []), + SFX('Cannon fire', 0x03, 0x07, 0x223D, []), SFX('Damage to enemy; $0BEX.4=1', 0x03, 0x08, 0x21E6, []), + SFX('Enemy death', 0x03, 0x09, 0x21C1, []), SFX('Collecting rupee', 0x03, 0x0A, 0x21A9, []), + SFX('Collecting heart', 0x03, 0x0B, 0x2198, []), + SFX('Non-blank text character', 0x03, 0x0C, 0x218E, []), + SFX('HUD heart (used explicitly by sanc heart?)', 0x03, 0x0D, 0x21B5, []), + SFX('Opening chest', 0x03, 0x0E, 0x2182, []), + SFX('♪Do do do doooooo♫', 0x03, 0x0F, 0x24B9, [0x3C, 0x3D, 0x3E, 0x3F]), + SFX('Opening/Closing map (paired)', 0x03, 0x10, 0x216D, [0x3b]), + SFX('Opening item menu/Bomb shop guy breathing', 0x03, 0x11, 0x214F, []), + SFX('Closing item menu/Bomb shop guy breathing', 0x03, 0x12, 0x215E, []), + SFX('Throwing object (sprites use it as well)/Stalfos jump', 0x03, 0x13, 0x213B, []), + SFX('Key door/Trinecks/Dash key landing/Stalfos Knight collapse', 0x03, 0x14, 0x246C, []), + SFX('Door closing/OW door opening/Chest opening (w/ $29 in $012E)', 0x03, 0x15, 0x212F, []), + SFX('Armos Knight thud', 0x03, 0x16, 0x2123, []), SFX('Rat squeak', 0x03, 0x17, 0x25A6, []), + SFX('Dragging/Mantle moving', 0x03, 0x18, 0x20DD, []), + SFX('Fireball/Laser shot; Somehow used by Trinexx???', 0x03, 0x19, 0x250A, []), + SFX('Chest reveal jingle ', 0x03, 0x1A, 0x1E8A, [0x38]), + SFX('Puzzle jingle', 0x03, 0x1B, 0x20B6, [0x3a]), SFX('Damage to enemy', 0x03, 0x1C, 0x1A62, []), + SFX('Potion refill/Magic drain', 0x03, 0x1D, 0x20A6, []), + SFX('Flapping (Duck/Cucco swarm/Ganon bats/Keese/Raven/Vulture)', 0x03, 0x1E, 0x2091, []), + SFX('Link falling', 0x03, 0x1F, 0x204B, []), SFX('Menu/Text cursor moved', 0x03, 0x20, 0x276C, []), + SFX('Damage to boss', 0x03, 0x21, 0x27E2, []), SFX('Boss dying/Deleting file', 0x03, 0x22, 0x26CF, []), + SFX('Spin attack/Medallion swoosh', 0x03, 0x23, 0x2001, [0x39]), + SFX('OW map perspective change', 0x03, 0x24, 0x2043, []), + SFX('Pressure switch', 0x03, 0x25, 0x1E9D, []), + SFX('Lightning/Game over/Laser/Ganon bat/Trinexx lunge', 0x03, 0x26, 0x1E7B, []), + SFX('Agahnim charge', 0x03, 0x27, 0x1E40, []), SFX('Agahnim/Ganon teleport', 0x03, 0x28, 0x26F7, []), + SFX('Agahnim shot', 0x03, 0x29, 0x1E21, []), + SFX('Somaria/Byrna/Ether spell/Helma fire ball', 0x03, 0x2A, 0x1E12, []), + SFX('Electrocution', 0x03, 0x2B, 0x1DF3, []), SFX('Bees', 0x03, 0x2C, 0x1DC0, []), + SFX('Milestone, also via text', 0x03, 0x2D, 0x1DA9, [0x37]), + SFX('Collecting heart container', 0x03, 0x2E, 0x1D5D, [0x35, 0x34]), + SFX('Collecting absorbable key', 0x03, 0x2F, 0x1D80, [0x33]), + SFX('Byrna spark/Item plop/Magic bat zap/Blob emerge', 0x03, 0x30, 0x1B53, []), + SFX('Sprite falling/Moldorm shuffle', 0x03, 0x31, 0x1ACA, []), + SFX('Bumper boing/Somaria punt/Blob transmutation/Sprite boings', 0x03, 0x32, 0x1A78, []), + SFX('Jingle (paired $2F→$33)', 0x03, 0x33, 0x1D93, [], True), + SFX('Depressing jingle (paired $2E→$35→$34)', 0x03, 0x34, 0x1D66, [], True), + SFX('Ugly jingle (paired $2E→$35→$34)', 0x03, 0x35, 0x1D73, [], True), + SFX('Wizzrobe shot/Helma fireball split/Mothula beam/Blue balls', 0x03, 0x36, 0x1AA7, []), + SFX('Dinky jingle (paired $2D→$37)', 0x03, 0x37, 0x1DB4, [], True), + SFX('Apathetic jingle (paired $1A→$38)', 0x03, 0x38, 0x1E93, [], True), + SFX('Quiet swish (paired $23→$39)', 0x03, 0x39, 0x2017, [], True), + SFX('Defective jingle (paired $1B→$3A)', 0x03, 0x3A, 0x20C0, [], True), + SFX('Petulant jingle (paired $10→$3B)', 0x03, 0x3B, 0x2176, [], True), + SFX('Triumphant jingle (paired $0F→$3C→$3D→$3E→$3F)', 0x03, 0x3C, 0x248A, [], True), + SFX('Less triumphant jingle ($0F→$3C→$3D→$3E→$3F)', 0x03, 0x3D, 0x2494, [], True), + SFX('"You tried, I guess" jingle (paired $0F→$3C→$3D→$3E→$3F)', 0x03, 0x3E, 0x249E, [], True), + SFX('"You didn\'t really try" jingle (paired $0F→$3C→$3D→$3E→$3F)', 0x03, 0x3F, 0x2480, [], True)] + return sfx_pool + + +def shuffle_sfx_data(): + sfx_pool = init_sfx_data() + sfx_map = {2: {}, 3: {}} + accompaniment_map = {2: set(), 3: set()} + candidates = [] + for sfx in sfx_pool: + sfx_map[sfx.sfx_set][sfx.orig_id] = sfx + if not sfx.accomp: + candidates.append((sfx.sfx_set, sfx.orig_id)) + else: + accompaniment_map[sfx.sfx_set].add(sfx.orig_id) + chained_sfx = [x for x in sfx_pool if len(x.chain) > 0] + + random.shuffle(candidates) + + # place chained sfx first + random.shuffle(chained_sfx) # todo: sort largest to smallest + chained_sfx = sorted(chained_sfx, key=lambda x: len(x.chain), reverse=True) + for chained in chained_sfx: + chosen_slot = next(x for x in candidates if len(accompaniment_map[x[0]]) - len(chained.chain) >= 0) + if chosen_slot is None: + raise Exception('Something went wrong with sfx chains') + chosen_set, chosen_id = chosen_slot + chained.target_set, chained.target_id = chosen_slot + chained.target_chain = [] + for downstream in chained.chain: + next_slot = accompaniment_map[chosen_set].pop() + ds_acc = sfx_map[chained.sfx_set][downstream] + ds_acc.target_set, ds_acc.target_id = chosen_set, next_slot + chained.target_chain.append(next_slot) + candidates.remove(chosen_slot) + sfx_pool.remove(chained) + + unchained_sfx = [x for x in sfx_pool if not x.accomp] + # do the rest + for sfx in unchained_sfx: + chosen_slot = candidates.pop() + sfx.target_set, sfx.target_id = chosen_slot + + return sfx_map + + +sfx_table = { + 2: 0x1a8c29, + 3: 0x1A8D25 +} + +# 0x1a8c29 +# d8059 + +sfx_accompaniment_table = { + 2: 0x1A8CA7, + 3: 0x1A8DA3 +} + + +def randomize_sfx(rom): + sfx_map = shuffle_sfx_data() + + for shuffled_sfx in sfx_map.values(): + for sfx in shuffled_sfx.values(): + base_address = sfx_table[sfx.target_set] + rom.write_bytes(base_address + (sfx.target_id * 2) - 2, int16_as_bytes(sfx.addr)) + ac_base = sfx_accompaniment_table[sfx.target_set] + last = sfx.target_id + if sfx.target_chain: + for chained in sfx.target_chain: + rom.write_byte(ac_base + last - 1, chained) + last = chained + rom.write_byte(ac_base + last - 1, 0) + + + + + + + + + diff --git a/source/classes/constants.py b/source/classes/constants.py index 04cbde2e..e03fba44 100644 --- a/source/classes/constants.py +++ b/source/classes/constants.py @@ -107,7 +107,8 @@ SETTINGSTOPROCESS = { "menuspeed": "fastmenu", "owpalettes": "ow_palettes", "uwpalettes": "uw_palettes", - "reduce_flashing": "reduce_flashing" + "reduce_flashing": "reduce_flashing", + "shuffle_sfx": "shuffle_sfx", }, "generation": { "createspoiler": "create_spoiler", diff --git a/source/gui/adjust/overview.py b/source/gui/adjust/overview.py index 4ae57e2e..7e16b1a9 100644 --- a/source/gui/adjust/overview.py +++ b/source/gui/adjust/overview.py @@ -103,6 +103,7 @@ def adjust_page(top, parent, settings): "quickswap": "quickswap", "nobgm": "disablemusic", "reduce_flashing": "reduce_flashing", + "shuffle_sfx": "shuffle_sfx", } guiargs = Namespace() for option in options: From 37b4d04d4781c0f2b2460b15ea1c87edd724fa02 Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 22 Jul 2021 16:26:08 -0700 Subject: [PATCH 08/30] Inverted pathing fix (Castle S&Q may be required) --- DoorShuffle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index 2e6f8b44..1b05f3e0 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -1843,7 +1843,7 @@ def find_accessible_entrances(world, player, builder): elif world.mode[player] != 'inverted': start_regions = ['Links House', 'Sanctuary'] else: - start_regions = ['Inverted Links House', 'Inverted Dark Sanctuary'] + start_regions = ['Inverted Links House', 'Inverted Dark Sanctuary', 'Hyrule Castle Ledge'] regs = convert_regions(start_regions, world, player) visited_regions = set() visited_entrances = [] From 23846dc4756e491143b56362936bec82aafb6af2 Mon Sep 17 00:00:00 2001 From: aerinon Date: Thu, 22 Jul 2021 16:28:27 -0700 Subject: [PATCH 09/30] credits again --- Main.py | 2 +- RELEASENOTES.md | 3 +++ Rom.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Main.py b/Main.py index eb8380f3..720382f6 100644 --- a/Main.py +++ b/Main.py @@ -27,7 +27,7 @@ from Fill import sell_potions, sell_keys, balance_multiworld_progression, balanc from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops from Utils import output_path, parse_player_names -__version__ = '0.4.0.11u' +__version__ = '0.4.0.12u' class EnemizerError(RuntimeError): diff --git a/RELEASENOTES.md b/RELEASENOTES.md index cafdb92f..cc592f7b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -22,6 +22,9 @@ For accessibility, you now get a C or P indicator to the left of the magic bar o # Bug Fixes and Notes. +* 0.4.0.12 + * ER Inverted fix for HC Ledge + * Credits again * 0.4.0.11 * Some minor base rom fixes * Improved distribution of bombable/dashable doors diff --git a/Rom.py b/Rom.py index 5c61e5c2..57df5c7a 100644 --- a/Rom.py +++ b/Rom.py @@ -808,7 +808,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): write_int16(rom, 0x187010, credits_total) # dynamic credits if credits_total != 216: # collection rate address: - cr_address = 0x2391F2 + cr_address = 0x2391F0 cr_pc = cr_address - 0x120000 # convert to pc mid_top, mid_bot = credits_digit((credits_total // 10) % 10) last_top, last_bot = credits_digit(credits_total % 10) From 5b39494edf30b9715c81f2852d3555d8655a5004 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 23 Jul 2021 09:45:12 -0700 Subject: [PATCH 10/30] Credit collection rate refactor Music fixes and moving hooks --- RELEASENOTES.md | 3 ++- Rom.py | 14 +++++++------- asm/drhooks.asm | 11 +++++++++++ asm/normal.asm | 2 +- data/base2current.bps | Bin 136225 -> 136267 bytes 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index cc592f7b..923ae974 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -24,7 +24,8 @@ For accessibility, you now get a C or P indicator to the left of the magic bar o * 0.4.0.12 * ER Inverted fix for HC Ledge - * Credits again + * Credits again - hopefully for good + * Incorporated music fixes for now (may revisit later) * 0.4.0.11 * Some minor base rom fixes * Improved distribution of bombable/dashable doors diff --git a/Rom.py b/Rom.py index 57df5c7a..6d1b2455 100644 --- a/Rom.py +++ b/Rom.py @@ -30,7 +30,7 @@ from EntranceShuffle import door_addresses, exit_ids JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '25dd18672e1234c85900f5b2155e7e4f' +RANDOMIZERBASEHASH = '9c2878d1035bb3889784906a55a92a26' class JsonRom(object): @@ -807,17 +807,17 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): write_int16(rom, 0x187010, credits_total) # dynamic credits if credits_total != 216: - # collection rate address: - cr_address = 0x2391F0 + # collection rate address (hi): + cr_address = 0x238057 cr_pc = cr_address - 0x120000 # convert to pc mid_top, mid_bot = credits_digit((credits_total // 10) % 10) last_top, last_bot = credits_digit(credits_total % 10) # top half - rom.write_byte(cr_pc+0x1c, mid_top) - rom.write_byte(cr_pc+0x1d, last_top) + rom.write_byte(cr_pc+0x1, mid_top) + rom.write_byte(cr_pc+0x2, last_top) # bottom half - rom.write_byte(cr_pc+0x3a, mid_bot) - rom.write_byte(cr_pc+0x3b, last_bot) + rom.write_byte(cr_pc+0x1f, mid_bot) + rom.write_byte(cr_pc+0x20, last_bot) # patch medallion requirements if world.required_medallions[player][0] == 'Bombos': diff --git a/asm/drhooks.asm b/asm/drhooks.asm index 2824771e..86ae1ff1 100644 --- a/asm/drhooks.asm +++ b/asm/drhooks.asm @@ -179,6 +179,17 @@ JSL BlindsAtticHint : NOP #2 org $1cfd69 Main_ShowTextMessage: +; Conditionally disable UW music changes in Door Rando +org $028ADB ; <- Bank02.asm:2088-2095 (LDX.b #$14 : LDA $A0 ...) +JSL.l Underworld_DoorDown_Entry : CPX #$10 +db $B0, $21 ; BCS $028B04 +BRA + : NOP #6 : + + +org $02C3F2 ; <- Bank02.asm:10521 Unused call +Underworld_DoorDown_Call: +org $02C3F3 +dw $8AD9 ; address of Bank02.asm:2085 + ; These two, if enabled together, have implications for vanilla BK doors in IP/Hera/Mire ; IPBJ is common enough to consider not doing this. Mire is not a concern for vanilla - maybe glitched modes ; Hera BK door back can be seen with Pot clipping - likely useful for no logic seeds diff --git a/asm/normal.asm b/asm/normal.asm index a8ab9597..aabb24de 100644 --- a/asm/normal.asm +++ b/asm/normal.asm @@ -398,7 +398,7 @@ StraightStairsTrapDoor: .animateTraps lda #$05 : sta $11 inc $0468 : stz $068e : stz $0690 - ++ rtl + ++ JSL Underworld_DoorDown_Call : rtl + JML Dungeon_ApproachFixedColor ; what we wrote over } diff --git a/data/base2current.bps b/data/base2current.bps index 53bd7d8680aa4516815cb90e352fe3ea90cbc137..a904b07d50f9fadac099414d033b0c27b309563b 100644 GIT binary patch delta 8235 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 qB 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 From 367a7be068d13478f568878e53f7b29fb1e32780 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 23 Jul 2021 10:08:41 -0700 Subject: [PATCH 11/30] Update notes --- RELEASENOTES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 923ae974..ed16c714 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -26,6 +26,7 @@ For accessibility, you now get a C or P indicator to the left of the magic bar o * ER Inverted fix for HC Ledge * Credits again - hopefully for good * Incorporated music fixes for now (may revisit later) + * Secure random re-incorporated * 0.4.0.11 * Some minor base rom fixes * Improved distribution of bombable/dashable doors From c522a1b001e35c9c1cd2e92d662165ca1726ae68 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 23 Jul 2021 08:39:31 -0700 Subject: [PATCH 12/30] Aga Tower shouldn't choose inverted links house if not shuffled --- EntranceShuffle.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index abfe4332..1b8ce162 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -1446,7 +1446,7 @@ def link_inverted_entrances(world, player): # shuffle aga door first. if it's on hc ledge, then one other hc ledge door has to be must_exit all_entrances_aga = lw_entrances + dw_entrances - aga_doors = [i for i in all_entrances_aga] + aga_doors = [i for i in all_entrances_aga if world.shufflelinks[player] or i != 'Inverted Links House'] random.shuffle(aga_doors) aga_door = aga_doors.pop() @@ -1589,8 +1589,9 @@ def link_inverted_entrances(world, player): hc_ledge_entrances = ['Hyrule Castle Entrance (West)', 'Hyrule Castle Entrance (East)', 'Inverted Ganons Tower'] # shuffle aga door. if it's on hc ledge, then one other hc ledge door has to be must_exit - aga_door = random.choice(entrances) - + aga_choices = [x for x in entrances if world.shufflelinks[player] or x != 'Inverted Links House'] + aga_door = random.choice(aga_choices) + if aga_door in hc_ledge_entrances: hc_ledge_entrances.remove(aga_door) From bfd5c5ceebf7a916e6f65b0751e00fa5a1fe1c81 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 23 Jul 2021 10:09:54 -0700 Subject: [PATCH 13/30] Update notes --- RELEASENOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ed16c714..0ccceb80 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -23,7 +23,7 @@ For accessibility, you now get a C or P indicator to the left of the magic bar o # Bug Fixes and Notes. * 0.4.0.12 - * ER Inverted fix for HC Ledge + * ER Inverted fix for HC Ledge, and Aga Tower choosing Links House incorrectly * Credits again - hopefully for good * Incorporated music fixes for now (may revisit later) * Secure random re-incorporated From 051a47e0cde59e75f26bd1dfcb9c739377095605 Mon Sep 17 00:00:00 2001 From: StructuralMike <66819228+StructuralMike@users.noreply.github.com> Date: Fri, 23 Jul 2021 20:35:48 +0200 Subject: [PATCH 14/30] Bomblogic added --- BaseClasses.py | 6 ++- CLI.py | 2 + ItemList.py | 47 +++++++++++-------- Items.py | 2 +- Main.py | 2 + Mystery.py | 2 + Rom.py | 9 ++-- Rules.py | 2 +- resources/app/cli/args.json | 4 ++ resources/app/cli/lang/en.json | 1 + resources/app/gui/lang/en.json | 1 + resources/app/gui/randomize/item/widgets.json | 1 + source/classes/constants.py | 1 + 13 files changed, 54 insertions(+), 26 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 0e3e8af4..42acdefe 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -114,6 +114,7 @@ class World(object): set_player_attr('compassshuffle', False) set_player_attr('keyshuffle', False) set_player_attr('bigkeyshuffle', False) + set_player_attr('bomblogic', False) set_player_attr('difficulty_requirements', None) set_player_attr('boss_shuffle', 'none') set_player_attr('enemy_shuffle', 'none') @@ -686,8 +687,7 @@ class CollectionState(object): # In the future, this can be used to check if the player starts without bombs def can_use_bombs(self, player): - StartingBombs = True - return StartingBombs or self.has('Bomb Upgrade (+10)', player) + return (not self.world.bomblogic[player] or self.has('Bomb Upgrade (+10)', player)) def can_hit_crystal(self, player): return (self.can_use_bombs(player) @@ -2013,6 +2013,7 @@ class Spoiler(object): 'logic': self.world.logic, 'mode': self.world.mode, 'retro': self.world.retro, + 'bomblogic': self.world.bomblogic, 'weapons': self.world.swords, 'goal': self.world.goal, 'shuffle': self.world.shuffle, @@ -2111,6 +2112,7 @@ class Spoiler(object): outfile.write('Experimental: %s\n' % ('Yes' if self.metadata['experimental'][player] else 'No')) outfile.write('Key Drops shuffled: %s\n' % ('Yes' if self.metadata['keydropshuffle'][player] else 'No')) outfile.write(f"Shopsanity: {'Yes' if self.metadata['shopsanity'][player] else 'No'}\n") + outfile.write('Bomblogic: %s\n' % ('Yes' if self.metadata['bomblogic'][player] else 'No')) if self.doors: outfile.write('\n\nDoors:\n\n') outfile.write('\n'.join( diff --git a/CLI.py b/CLI.py index d87e1e2c..10fb211c 100644 --- a/CLI.py +++ b/CLI.py @@ -96,6 +96,7 @@ def parse_cli(argv, no_defaults=False): for name in ['logic', 'mode', 'swords', 'goal', 'difficulty', 'item_functionality', 'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid', 'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory', + 'bomblogic', 'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max', 'triforce_min_difference', 'triforce_goal', 'triforce_pool', 'shufflelinks', 'pseudoboots', 'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters', @@ -126,6 +127,7 @@ def parse_settings(): settings = { "lang": "en", "retro": False, + "bomblogic": False, "mode": "open", "logic": "noglitches", "goal": "ganon", diff --git a/ItemList.py b/ItemList.py index a16219f4..a1d31968 100644 --- a/ItemList.py +++ b/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', - 'retro', + 'retro', 'bomblogic', 'extras', 'progressive_sword_limit', 'progressive_shield_limit', 'progressive_armor_limit', 'progressive_bottle_limit', 'progressive_bow_limit', 'heart_piece_limit', 'boss_heart_container_limit']) @@ -61,6 +61,7 @@ difficulties = { timedohko = ['Green Clock'] * 25, timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10, retro = ['Small Key (Universal)'] * 18 + ['Rupees (20)'] * 10, + bomblogic = ['Bomb Upgrade (+10)'] * 2, extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra], progressive_sword_limit = 4, progressive_shield_limit = 3, @@ -86,6 +87,7 @@ difficulties = { timedohko = ['Green Clock'] * 25, timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10, retro = ['Small Key (Universal)'] * 13 + ['Rupees (5)'] * 15, + bomblogic = ['Bomb Upgrade (+10)'] * 2, extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra], progressive_sword_limit = 3, progressive_shield_limit = 2, @@ -111,6 +113,7 @@ difficulties = { timedohko = ['Green Clock'] * 20 + ['Red Clock'] * 5, timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10, retro = ['Small Key (Universal)'] * 13 + ['Rupees (5)'] * 15, + bomblogic = ['Bomb Upgrade (+10)'] * 2, extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra], progressive_sword_limit = 2, progressive_shield_limit = 1, @@ -251,10 +254,10 @@ def generate_itempool(world, player): # set up item pool 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.bomblogic[player], world.customitemarray) world.rupoor_cost = min(world.customitemarray[player]["rupoorcost"], 9999) else: - (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], world.logic[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.bomblogic[player], world.doorShuffle[player], world.logic[player]) if player in world.pool_adjustment.keys(): amt = world.pool_adjustment[player] @@ -284,7 +287,7 @@ def generate_itempool(world, player): if item in ['Hammer', 'Fire Rod', 'Cane of Somaria', 'Cane of Byrna']: if item not in possible_weapons: possible_weapons.append(item) - if item in ['Bombs (10)']: + if not world.bomblogic[player] and item in ['Bombs (10)']: if item not in possible_weapons and world.doorShuffle[player] != 'crossed': possible_weapons.append(item) starting_weapon = random.choice(possible_weapons) @@ -709,7 +712,7 @@ rupee_chart = {'Rupee (1)': 1, 'Rupees (5)': 5, 'Rupees (20)': 20, 'Rupees (50)' 'Rupees (100)': 100, 'Rupees (300)': 300} -def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, goal, mode, swords, retro, door_shuffle, logic): +def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, goal, mode, swords, retro, bomblogic, door_shuffle, logic): pool = [] placed_items = {} precollected_items = [] @@ -756,6 +759,11 @@ def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, diff = difficulties[difficulty] pool.extend(diff.baseitems) + if bomblogic: + pool = [item.replace('Bomb Upgrade (+5)','Rupees (5)') for item in pool] + pool = [item.replace('Bomb Upgrade (+10)','Rupees (5)') for item in pool] + pool.extend(diff.bomblogic) + # expert+ difficulties produce the same contents for # all bottles, since only one bottle is available if diff.same_bottle: @@ -850,7 +858,7 @@ def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer, pool.extend(['Small Key (Universal)']) 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): +def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, bomblogic, customitemarray): if isinstance(customitemarray,dict) and 1 in customitemarray: customitemarray = customitemarray[1] pool = [] @@ -966,20 +974,21 @@ def test(): for shuffle in ['full', 'insanity_legacy']: for logic in ['noglitches', 'minorglitches', 'owglitches', 'nologic']: for retro in [True, False]: - for door_shuffle in ['basic', 'crossed', 'vanilla']: - out = get_pool_core(progressive, shuffle, difficulty, 30, timer, goal, mode, swords, retro, door_shuffle, logic) - count = len(out[0]) + len(out[1]) + for bomblogic in [True, False]: + for door_shuffle in ['basic', 'crossed', 'vanilla']: + out = get_pool_core(progressive, shuffle, difficulty, 30, timer, goal, mode, swords, retro, bomblogic, door_shuffle, logic) + count = len(out[0]) + len(out[1]) - correct_count = total_items_to_place - if goal == 'pedestal' and swords != 'vanilla': - # pedestal goals generate one extra item - correct_count += 1 - if retro: - correct_count += 28 - try: - assert count == correct_count, "expected {0} items but found {1} items for {2}".format(correct_count, count, (progressive, shuffle, difficulty, timer, goal, mode, swords, retro)) - except AssertionError as e: - print(e) + correct_count = total_items_to_place + if goal == 'pedestal' and swords != 'vanilla': + # pedestal goals generate one extra item + correct_count += 1 + if retro: + correct_count += 28 + try: + assert count == correct_count, "expected {0} items but found {1} items for {2}".format(correct_count, count, (progressive, shuffle, difficulty, timer, goal, mode, swords, retro, bomblogic)) + except AssertionError as e: + print(e) if __name__ == '__main__': test() diff --git a/Items.py b/Items.py index 808a0740..279cc33d 100644 --- a/Items.py +++ b/Items.py @@ -81,7 +81,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche 'Single Bomb': (False, False, None, 0x27, 5, 'I make things\ngo BOOM! But\njust once.', 'and the explosion', 'the bomb-holding kid', 'firecracker for sale', 'blend fungus into bomb', '\'splosion boy explodes again', 'a bomb'), 'Bombs (3)': (False, False, None, 0x28, 15, 'I make things\ngo triple\nBOOM!!!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'three bombs'), 'Bombs (10)': (False, False, None, 0x31, 50, 'I make things\ngo BOOM! Ten\ntimes!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'ten bombs'), - 'Bomb Upgrade (+10)': (False, False, None, 0x52, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), + 'Bomb Upgrade (+10)': (True, False, None, 0x52, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), 'Bomb Upgrade (+5)': (False, False, None, 0x51, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), 'Blue Mail': (False, True, None, 0x22, 50, 'Now you\'re a\nblue elf!', 'and the banana hat', 'the protected kid', 'banana hat for sale', 'the clothing store', 'tailor boy banana hatted again', 'the blue mail'), 'Red Mail': (False, True, None, 0x23, 100, 'Now you\'re a\nred elf!', 'and the eggplant hat', 'well-protected kid', 'purple hat for sale', 'the nice clothing store', 'tailor boy fears nothing again', 'the red mail'), diff --git a/Main.py b/Main.py index 8909301a..06ccf51c 100644 --- a/Main.py +++ b/Main.py @@ -69,6 +69,7 @@ def main(args, seed=None, fish=None): world.compassshuffle = args.compassshuffle.copy() world.keyshuffle = args.keyshuffle.copy() world.bigkeyshuffle = args.bigkeyshuffle.copy() + world.bomblogic = args.bomblogic.copy() world.crystals_needed_for_ganon = {player: random.randint(0, 7) if args.crystals_ganon[player] == 'random' else int(args.crystals_ganon[player]) for player in range(1, world.players + 1)} world.crystals_needed_for_gt = {player: random.randint(0, 7) if args.crystals_gt[player] == 'random' else int(args.crystals_gt[player]) for player in range(1, world.players + 1)} world.crystals_ganon_orig = args.crystals_ganon.copy() @@ -372,6 +373,7 @@ def copy_world(world): ret.compassshuffle = world.compassshuffle.copy() ret.keyshuffle = world.keyshuffle.copy() ret.bigkeyshuffle = world.bigkeyshuffle.copy() + ret.bomblogic = world.bomblogic.copy() ret.crystals_needed_for_ganon = world.crystals_needed_for_ganon.copy() ret.crystals_needed_for_gt = world.crystals_needed_for_gt.copy() ret.crystals_ganon_orig = world.crystals_ganon_orig.copy() diff --git a/Mystery.py b/Mystery.py index d3e3bddf..3786ae15 100644 --- a/Mystery.py +++ b/Mystery.py @@ -176,6 +176,8 @@ def roll_settings(weights): ret.retro = True ret.retro = get_choice('retro') == 'on' # this overrides world_state if used + ret.bomblogic = get_choice('bomblogic') == 'on' + ret.hints = get_choice('hints') == 'on' ret.swords = {'randomized': 'random', diff --git a/Rom.py b/Rom.py index 40249d56..bbf76726 100644 --- a/Rom.py +++ b/Rom.py @@ -1032,7 +1032,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_bytes(0x184000, [ # original_item, limit, replacement_item, filler 0x12, 0x01, 0x35, 0xFF, # lamp -> 5 rupees - 0x51, 0x06, 0x52, 0xFF, # 6 +5 bomb upgrades -> +10 bomb upgrade + 0x51, 0x00 if world.bomblogic[player] else 0x06, 0x31 if world.bomblogic[player] else 0x52, 0xFF, # 6 +5 bomb upgrades -> +10 bomb upgrade. If bomblogic -> turns into Bombs (10) 0x53, 0x06, 0x54, 0xFF, # 6 +5 arrow upgrades -> +10 arrow upgrade 0x58, 0x01, 0x36 if world.retro[player] else 0x43, 0xFF, # silver arrows -> single arrow (red 20 in retro mode) 0x3E, difficulty.boss_heart_container_limit, 0x47, 0xff, # boss heart -> green 20 @@ -1169,7 +1169,10 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): equip[0x36C] = 0x18 equip[0x36D] = 0x18 equip[0x379] = 0x68 - starting_max_bombs = 10 + if world.bomblogic[player]: + starting_max_bombs = 0 + else: + starting_max_bombs = 10 starting_max_arrows = 30 startingstate = CollectionState(world) @@ -1461,7 +1464,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_bytes(0x180188, [0, 0, 10]) # Zelda respawn refills (magic, bombs, arrows) rom.write_bytes(0x18018B, [0, 0, 10]) # Mantle respawn refills (magic, bombs, arrows) bow_max, bow_small = 70, 10 - elif uncle_location.item is not None and uncle_location.item.name in ['Bombs (10)']: + elif uncle_location.item is not None and uncle_location.item.name in ['Bomb Upgrade (+10)' if world.bomblogic[player] else 'Bombs (10)']: rom.write_byte(0x18004E, 2) # Escape Fill (bombs) rom.write_bytes(0x180185, [0, 50, 0]) # Uncle respawn refills (magic, bombs, arrows) rom.write_bytes(0x180188, [0, 3, 0]) # Zelda respawn refills (magic, bombs, arrows) diff --git a/Rules.py b/Rules.py index 3762b9bb..75deec4a 100644 --- a/Rules.py +++ b/Rules.py @@ -1160,7 +1160,7 @@ def standard_rules(world, player): def bomb_escape_rule(): loc = world.get_location("Link's Uncle", player) - return loc.item and loc.item.name == 'Bombs (10)' + return loc.item and loc.item.name in ['Bomb Upgrade (+10)' if world.bomblogic[player] else 'Bombs (10)'] def standard_escape_rule(state): return state.can_kill_most_things(player) or bomb_escape_rule() diff --git a/resources/app/cli/args.json b/resources/app/cli/args.json index 47bb3987..817e2607 100644 --- a/resources/app/cli/args.json +++ b/resources/app/cli/args.json @@ -220,6 +220,10 @@ "type": "bool", "help": "suppress" }, + "bomblogic": { + "action": "store_true", + "type": "bool" + }, "retro": { "action": "store_true", "type": "bool" diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index ef1a8f3d..dffd41ff 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -263,6 +263,7 @@ "and a few other little things make this more like Zelda-1. (default: %(default)s)" ], "pseudoboots": [ " Players starts with pseudo boots that allow dashing but no item checks (default: %(default)s"], + "bomblogic": ["Start with 0 bomb capacity. Two capacity upgrades (+10) are added to the pool (default: %(default)s)" ], "startinventory": [ "Specifies a list of items that will be in your starting inventory (separated by commas). (default: %(default)s)" ], "usestartinventory": [ "Toggle usage of Starting Inventory." ], "custom": [ "Not supported." ], diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index 0d9e3836..2d8bf3f8 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -190,6 +190,7 @@ "randomizer.item.hints": "Include Helpful Hints", "randomizer.item.retro": "Retro mode (universal keys)", "randomizer.item.pseudoboots": "Start with Pseudo Boots", + "randomizer.item.bomblogic": "Bomblogic", "randomizer.item.worldstate": "World State", "randomizer.item.worldstate.standard": "Standard", diff --git a/resources/app/gui/randomize/item/widgets.json b/resources/app/gui/randomize/item/widgets.json index a6f10a14..15d049c8 100644 --- a/resources/app/gui/randomize/item/widgets.json +++ b/resources/app/gui/randomize/item/widgets.json @@ -1,6 +1,7 @@ { "checkboxes": { "retro": { "type": "checkbox" }, + "bomblogic": { "type": "checkbox" }, "shopsanity": { "type": "checkbox" }, "hints": { "type": "checkbox" diff --git a/source/classes/constants.py b/source/classes/constants.py index 04cbde2e..7c76913f 100644 --- a/source/classes/constants.py +++ b/source/classes/constants.py @@ -57,6 +57,7 @@ SETTINGSTOPROCESS = { "item": { "hints": "hints", "retro": "retro", + "bomblogic": "bomblogic", "shopsanity": "shopsanity", "pseudoboots": "pseudoboots", "worldstate": "mode", From cce5adc4538aff00c247c7150f378c77ab685c2c Mon Sep 17 00:00:00 2001 From: StructuralMike <66819228+StructuralMike@users.noreply.github.com> Date: Sat, 24 Jul 2021 14:21:22 +0200 Subject: [PATCH 15/30] Good bee cave & spiral cave logic for bombs Good bee cave requires bombs to access. Spiral cave is never assumed to be transversable as a super bunny, so it makes sense to force bombs OR can_kill_most_things if the cave is in the LW. --- BaseClasses.py | 1 + Rules.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/BaseClasses.py b/BaseClasses.py index 42acdefe..b7a80af7 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -719,6 +719,7 @@ class CollectionState(object): def can_get_good_bee(self, player): cave = self.world.get_region('Good Bee Cave', player) return ( + self.can_use_bombs(player) and self.has_bottle(player) and self.has('Bug Catching Net', player) and (self.has_Boots(player) or (self.has_sword(player) and self.has('Quake', player))) and diff --git a/Rules.py b/Rules.py index 75deec4a..9560970d 100644 --- a/Rules.py +++ b/Rules.py @@ -576,9 +576,10 @@ def bomb_rules(world, player): for location in bombable_items: add_rule(world.get_location(location, player), lambda state: state.can_use_bombs(player)) - cave_kill_locations = ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right', 'Mini Moldorm Cave - Generous Guy'] + cave_kill_locations = ['Mini Moldorm Cave - Far Left', 'Mini Moldorm Cave - Far Right', 'Mini Moldorm Cave - Left', 'Mini Moldorm Cave - Right', 'Mini Moldorm Cave - Generous Guy', 'Spiral Cave'] for location in cave_kill_locations: add_rule(world.get_location(location, player), lambda state: state.can_kill_most_things(player) or state.can_use_bombs(player)) + add_rule(world.get_entrance('Spiral Cave (top to bottom)', player), lambda state: state.can_kill_most_things(player) or state.can_use_bombs(player)) paradox_switch_chests = ['Paradox Cave Lower - Far Left', 'Paradox Cave Lower - Left', 'Paradox Cave Lower - Right', 'Paradox Cave Lower - Far Right', 'Paradox Cave Lower - Middle'] for location in paradox_switch_chests: From 779c7d78c0f01a8924a18a9baa3d7bc64f7827bd Mon Sep 17 00:00:00 2001 From: StructuralMike <66819228+StructuralMike@users.noreply.github.com> Date: Sat, 24 Jul 2021 17:22:48 +0200 Subject: [PATCH 16/30] New hookshot cave region definitions --- EntranceShuffle.py | 30 +++++++++++++++++++----------- InvertedRegions.py | 7 +++++-- PotShuffle.py | 6 +++--- Regions.py | 7 +++++-- Rules.py | 5 +++-- 5 files changed, 35 insertions(+), 20 deletions(-) diff --git a/EntranceShuffle.py b/EntranceShuffle.py index 1b8ce162..1c1a6ab8 100644 --- a/EntranceShuffle.py +++ b/EntranceShuffle.py @@ -2373,7 +2373,7 @@ Cave_Exits_Base = [['Elder House Exit (East)', 'Elder House Exit (West)'], ['Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave Exit (East)'], ['Fairy Ascension Cave Exit (Bottom)', 'Fairy Ascension Cave Exit (Top)'], ['Bumper Cave Exit (Top)', 'Bumper Cave Exit (Bottom)'], - ['Hookshot Cave Exit (South)', 'Hookshot Cave Exit (North)']] + ['Hookshot Cave Back Exit', 'Hookshot Cave Front Exit']] Cave_Exits_Base += [('Superbunny Cave Exit (Bottom)', 'Superbunny Cave Exit (Top)'), ('Spiral Cave Exit (Top)', 'Spiral Cave Exit')] @@ -3115,6 +3115,10 @@ mandatory_connections = [('Links House S&Q', 'Links House'), ('Dark Death Mountain Drop (West)', 'Dark Death Mountain (West Bottom)'), ('East Death Mountain (Top) Mirror Spot', 'East Death Mountain (Top)'), ('Superbunny Cave Climb', 'Superbunny Cave (Top)'), + ('Hookshot Cave Front to Middle', 'Hookshot Cave (Middle)'), + ('Hookshot Cave Middle to Front', 'Hookshot Cave (Front)'), + ('Hookshot Cave Middle to Back', 'Hookshot Cave (Back)'), + ('Hookshot Cave Back to Middle', 'Hookshot Cave (Middle)'), ('Turtle Rock Teleporter', 'Turtle Rock (Top)'), ('Turtle Rock Drop', 'Dark Death Mountain (Top)'), ('Floating Island Drop', 'Dark Death Mountain (Top)'), @@ -3233,6 +3237,10 @@ inverted_mandatory_connections = [('Links House S&Q', 'Inverted Links House'), ('Turtle Rock Tail Drop', 'Turtle Rock (Top)'), ('Turtle Rock Drop', 'Dark Death Mountain'), ('Superbunny Cave Climb', 'Superbunny Cave (Top)'), + ('Hookshot Cave Front to Middle', 'Hookshot Cave (Middle)'), + ('Hookshot Cave Middle to Front', 'Hookshot Cave (Front)'), + ('Hookshot Cave Middle to Back', 'Hookshot Cave (Back)'), + ('Hookshot Cave Back to Middle', 'Hookshot Cave (Middle)'), ('Desert Ledge Drop', 'Light World'), ('Floating Island Drop', 'Dark Death Mountain'), ('Dark Lake Hylia Central Island Teleporter', 'Lake Hylia Central Island'), @@ -3428,16 +3436,16 @@ default_connections = [('Links House', 'Links House'), ('Dark Desert Hint', 'Dark Desert Hint'), ('Dark Desert Fairy', 'Dark Desert Healer Fairy'), ('Spike Cave', 'Spike Cave'), - ('Hookshot Cave', 'Hookshot Cave'), + ('Hookshot Cave', 'Hookshot Cave (Front)'), ('Superbunny Cave (Top)', 'Superbunny Cave (Top)'), ('Cave Shop (Dark Death Mountain)', 'Cave Shop (Dark Death Mountain)'), ('Dark Death Mountain Fairy', 'Dark Death Mountain Healer Fairy'), ('Superbunny Cave (Bottom)', 'Superbunny Cave (Bottom)'), ('Superbunny Cave Exit (Top)', 'Dark Death Mountain (Top)'), ('Superbunny Cave Exit (Bottom)', 'Dark Death Mountain (East Bottom)'), - ('Hookshot Cave Exit (South)', 'Dark Death Mountain (Top)'), - ('Hookshot Cave Exit (North)', 'Death Mountain Floating Island (Dark World)'), - ('Hookshot Cave Back Entrance', 'Hookshot Cave'), + ('Hookshot Cave Front Exit', 'Dark Death Mountain (Top)'), + ('Hookshot Cave Back Exit', 'Death Mountain Floating Island (Dark World)'), + ('Hookshot Cave Back Entrance', 'Hookshot Cave (Back)'), ('Mimic Cave', 'Mimic Cave'), ('Pyramid Hole', 'Pyramid'), @@ -3562,13 +3570,13 @@ inverted_default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing' ('Dark Desert Hint', 'Dark Desert Hint'), ('Dark Desert Fairy', 'Dark Desert Healer Fairy'), ('Spike Cave', 'Spike Cave'), - ('Hookshot Cave', 'Hookshot Cave'), + ('Hookshot Cave', 'Hookshot Cave (Front)'), ('Superbunny Cave (Top)', 'Superbunny Cave (Top)'), ('Cave Shop (Dark Death Mountain)', 'Cave Shop (Dark Death Mountain)'), ('Superbunny Cave (Bottom)', 'Superbunny Cave (Bottom)'), ('Superbunny Cave Exit (Bottom)', 'Dark Death Mountain (East Bottom)'), - ('Hookshot Cave Exit (North)', 'Death Mountain Floating Island (Dark World)'), - ('Hookshot Cave Back Entrance', 'Hookshot Cave'), + ('Hookshot Cave Back Exit', 'Death Mountain Floating Island (Dark World)'), + ('Hookshot Cave Back Entrance', 'Hookshot Cave (Back)'), ('Mimic Cave', 'Mimic Cave'), ('Inverted Pyramid Hole', 'Pyramid'), ('Inverted Links House', 'Inverted Links House'), @@ -3589,7 +3597,7 @@ inverted_default_connections = [('Waterfall of Wishing', 'Waterfall of Wishing' ('Death Mountain Return Cave (East)', 'Death Mountain Return Cave'), ('Death Mountain Return Cave Exit (West)', 'Death Mountain'), ('Death Mountain Return Cave Exit (East)', 'Death Mountain'), - ('Hookshot Cave Exit (South)', 'Dark Death Mountain'), + ('Hookshot Cave Front Exit', 'Dark Death Mountain'), ('Superbunny Cave Exit (Top)', 'Dark Death Mountain'), ('Pyramid Exit', 'Light World'), ('Inverted Pyramid Entrance', 'Bottom of Pyramid')] @@ -3937,8 +3945,8 @@ exit_ids = {'Links House Exit': (0x01, 0x00), 'Bumper Cave Exit (Bottom)': (0x16, 0x17), 'Superbunny Cave Exit (Top)': (0x14, 0x15), 'Superbunny Cave Exit (Bottom)': (0x13, 0x14), - 'Hookshot Cave Exit (South)': (0x3A, 0x3B), - 'Hookshot Cave Exit (North)': (0x3B, 0x3C), + 'Hookshot Cave Front Exit': (0x3A, 0x3B), + 'Hookshot Cave Back Exit': (0x3B, 0x3C), 'Ganons Tower Exit': (0x37, 0x38), 'Inverted Ganons Tower Exit': (0x37, 0x38), 'Pyramid Exit': (0x36, 0x37), diff --git a/InvertedRegions.py b/InvertedRegions.py index d935ed28..589f6f87 100644 --- a/InvertedRegions.py +++ b/InvertedRegions.py @@ -199,8 +199,11 @@ def create_inverted_regions(world, player): create_cave_region(player, 'Superbunny Cave (Top)', 'a connector', ['Superbunny Cave - Top', 'Superbunny Cave - Bottom'], ['Superbunny Cave Exit (Top)']), create_cave_region(player, 'Superbunny Cave (Bottom)', 'a connector', None, ['Superbunny Cave Climb', 'Superbunny Cave Exit (Bottom)']), create_cave_region(player, 'Spike Cave', 'Spike Cave', ['Spike Cave']), - create_cave_region(player, 'Hookshot Cave', 'a connector', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Right', 'Hookshot Cave - Bottom Left'], - ['Hookshot Cave Exit (South)', 'Hookshot Cave Exit (North)']), + create_cave_region(player, 'Hookshot Cave (Front)', 'a connector', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Right', 'Hookshot Cave - Bottom Left'], + ['Hookshot Cave Front to Middle', 'Hookshot Cave Front Exit']), + create_cave_region(player, 'Hookshot Cave (Back)', 'a connector', None, ['Hookshot Cave Back to Middle', 'Hookshot Cave Back Exit']), + create_cave_region(player, 'Hookshot Cave (Middle)', 'a connector', None, ['Hookshot Cave Middle to Back', 'Hookshot Cave Middle to Front']), + create_dw_region(player, 'Death Mountain Floating Island (Dark World)', None, ['Floating Island Drop', 'Hookshot Cave Back Entrance']), create_cave_region(player, 'Mimic Cave', 'Mimic Cave', ['Mimic Cave']), diff --git a/PotShuffle.py b/PotShuffle.py index d62f52eb..a0c048bf 100644 --- a/PotShuffle.py +++ b/PotShuffle.py @@ -51,7 +51,7 @@ vanilla_pots = { 43: [Pot(16, 5, PotItem.Heart, 'PoD Sexy Statue'), Pot(44, 5, PotItem.Switch, 'PoD Sexy Statue'), Pot(16, 6, PotItem.Heart, 'PoD Sexy Statue'), Pot(44, 6, PotItem.Bomb, 'PoD Sexy Statue'), Pot(16, 7, PotItem.Heart, 'PoD Sexy Statue'), Pot(44, 7, PotItem.Bomb, 'PoD Sexy Statue'), Pot(146, 21, PotItem.Bomb, 'PoD Map Balcony'), Pot(170, 21, PotItem.FiveArrows, 'PoD Map Balcony'), Pot(146, 22, PotItem.Bomb, 'PoD Map Balcony'), Pot(170, 22, PotItem.FiveArrows, 'PoD Map Balcony')], - 44: [Pot(108, 24, PotItem.Heart, 'Hookshot Cave'), Pot(112, 24, PotItem.Heart, 'Hookshot Cave')], + 44: [Pot(108, 24, PotItem.Heart, 'Hookshot Cave (Middle)'), Pot(112, 24, PotItem.Heart, 'Hookshot Cave (Middle)')], 47: [Pot(28, 7, PotItem.Heart, 'Kakariko Well (top)'), Pot(32, 7, PotItem.Heart, 'Kakariko Well (top)'), Pot(28, 9, PotItem.FiveRupees, 'Kakariko Well (top)'), Pot(32, 9, PotItem.FiveRupees, 'Kakariko Well (top)'), Pot(172, 19, PotItem.FiveRupees, 'Kakariko Well (top)'), Pot(180, 19, PotItem.FiveRupees, 'Kakariko Well (top)'), Pot(104, 27, PotItem.Heart, 'Kakariko Well (bottom)'), Pot(104, 28, PotItem.Heart, 'Kakariko Well (bottom)')], 49: [Pot(92, 28, PotItem.Bomb, 'Hera Beetles'), Pot(96, 28, PotItem.Nothing, 'Hera Beetles')], @@ -66,8 +66,8 @@ vanilla_pots = { 55: [Pot(60, 6, PotItem.Key, 'Swamp Trench 1 Alcove'), Pot(48, 20, PotItem.Nothing, 'Swamp Trench 1 Key Ledge')], 56: [Pot(164, 12, PotItem.Bomb, 'Swamp Pot Row'), Pot(164, 13, PotItem.FiveRupees, 'Swamp Pot Row'), Pot(164, 18, PotItem.Bomb, 'Swamp Pot Row'), Pot(164, 19, PotItem.Key, 'Swamp Pot Row')], 57: [Pot(12, 20, PotItem.Heart, 'Skull Spike Corner'), Pot(48, 28, PotItem.FiveArrows, 'Skull Spike Corner'), Pot(100, 22, PotItem.SmallMagic, 'Skull Final Drop'), Pot(100, 26, PotItem.FiveArrows, 'Skull Final Drop')], - 60: [Pot(24, 8, PotItem.SmallMagic, 'Hookshot Cave'), Pot(64, 12, PotItem.FiveRupees, 'Hookshot Cave'), Pot(20, 14, PotItem.OneRupee, 'Hookshot Cave'), Pot(20, 19, PotItem.Nothing, 'Hookshot Cave'), - Pot(68, 18, PotItem.FiveRupees, 'Hookshot Cave'), Pot(96, 19, PotItem.Heart, 'Hookshot Cave'), Pot(64, 20, PotItem.FiveRupees, 'Hookshot Cave'), Pot(64, 26, PotItem.FiveRupees, 'Hookshot Cave')], + 60: [Pot(24, 8, PotItem.SmallMagic, 'Hookshot Cave (Front)'), Pot(64, 12, PotItem.FiveRupees, 'Hookshot Cave (Front)'), Pot(20, 14, PotItem.OneRupee, 'Hookshot Cave (Front)'), Pot(20, 19, PotItem.Nothing, 'Hookshot Cave (Front)'), + Pot(68, 18, PotItem.FiveRupees, 'Hookshot Cave (Front)'), Pot(96, 19, PotItem.Heart, 'Hookshot Cave (Front)'), Pot(64, 20, PotItem.FiveRupees, 'Hookshot Cave (Front)'), Pot(64, 26, PotItem.FiveRupees, 'Hookshot Cave (Front)')], 61: [Pot(76, 12, PotItem.Bomb, 'GT Mini Helmasaur Room'), Pot(112, 12, PotItem.Bomb, 'GT Mini Helmasaur Room'), Pot(24, 22, PotItem.Heart, 'GT Crystal Inner Circle'), Pot(40, 22, PotItem.FiveArrows, 'GT Crystal Inner Circle'), Pot(32, 24, PotItem.Heart, 'GT Crystal Inner Circle'), Pot(20, 26, PotItem.FiveRupees, 'GT Crystal Inner Circle'), Pot(36, 26, PotItem.BigMagic, 'GT Crystal Inner Circle')], 62: [Pot(96, 6, PotItem.Bomb, 'Ice Stalfos Hint'), Pot(100, 6, PotItem.SmallMagic, 'Ice Stalfos Hint'), Pot(88, 10, PotItem.Heart, 'Ice Stalfos Hint'), Pot(92, 10, PotItem.SmallMagic, 'Ice Stalfos Hint')], diff --git a/Regions.py b/Regions.py index b2af454a..35a7eda3 100644 --- a/Regions.py +++ b/Regions.py @@ -190,8 +190,11 @@ def create_regions(world, player): create_cave_region(player, 'Superbunny Cave (Top)', 'a connector', ['Superbunny Cave - Top', 'Superbunny Cave - Bottom'], ['Superbunny Cave Exit (Top)']), create_cave_region(player, 'Superbunny Cave (Bottom)', 'a connector', None, ['Superbunny Cave Climb', 'Superbunny Cave Exit (Bottom)']), create_cave_region(player, 'Spike Cave', 'Spike Cave', ['Spike Cave']), - create_cave_region(player, 'Hookshot Cave', 'a connector', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Right', 'Hookshot Cave - Bottom Left'], - ['Hookshot Cave Exit (South)', 'Hookshot Cave Exit (North)']), + create_cave_region(player, 'Hookshot Cave (Front)', 'a connector', ['Hookshot Cave - Top Right', 'Hookshot Cave - Top Left', 'Hookshot Cave - Bottom Right', 'Hookshot Cave - Bottom Left'], + ['Hookshot Cave Front to Middle', 'Hookshot Cave Front Exit']), + create_cave_region(player, 'Hookshot Cave (Back)', 'a connector', None, ['Hookshot Cave Back to Middle', 'Hookshot Cave Back Exit']), + create_cave_region(player, 'Hookshot Cave (Middle)', 'a connector', None, ['Hookshot Cave Middle to Back', 'Hookshot Cave Middle to Front']), + create_dw_region(player, 'Death Mountain Floating Island (Dark World)', None, ['Floating Island Drop', 'Hookshot Cave Back Entrance', 'Floating Island Mirror Spot']), create_lw_region(player, 'Death Mountain Floating Island (Light World)', ['Floating Island']), create_dw_region(player, 'Turtle Rock (Top)', None, ['Turtle Rock Drop']), diff --git a/Rules.py b/Rules.py index 9560970d..cd65e748 100644 --- a/Rules.py +++ b/Rules.py @@ -561,7 +561,8 @@ def global_rules(world, player): def bomb_rules(world, player): bonkable_doors = ['Two Brothers House Exit (West)', 'Two Brothers House Exit (East)'] # Technically this is incorrectly defined, but functionally the same as what is intended. bombable_doors = ['Ice Rod Cave', 'Light World Bomb Hut', 'Light World Death Mountain Shop', 'Mini Moldorm Cave', - 'Hookshot Cave Exit (South)', 'Hookshot Cave Exit (North)', 'Dark Lake Hylia Ledge Fairy', 'Hype Cave', 'Brewery'] + 'Hookshot Cave Back to Middle', 'Hookshot Cave Front to Middle', 'Hookshot Cave Middle to Front','Hookshot Cave Middle to Back', + 'Dark Lake Hylia Ledge Fairy', 'Hype Cave', 'Brewery'] for entrance in bonkable_doors: add_rule(world.get_entrance(entrance, player), lambda state: state.can_use_bombs(player) or state.has_Boots(player)) for entrance in bombable_doors: @@ -1672,7 +1673,7 @@ def set_bunny_rules(world, player, inverted): # regions for the exits of multi-entrace caves/drops that bunny cannot pass # Note spiral cave may be technically passible, but it would be too absurd to require since OHKO mode is a thing. - bunny_impassable_caves = ['Bumper Cave', 'Two Brothers House', 'Hookshot Cave', + bunny_impassable_caves = ['Bumper Cave', 'Two Brothers House', 'Hookshot Cave (Middle)', 'Pyramid', 'Spiral Cave (Top)', 'Fairy Ascension Cave (Drop)'] bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', From c981b362d29ee8f0e01fd8bd918e31d046af3921 Mon Sep 17 00:00:00 2001 From: compiling <8335770+compiling@users.noreply.github.com> Date: Sun, 25 Jul 2021 18:15:11 +1000 Subject: [PATCH 17/30] Add warning for old python versions. --- Gui.py | 9 +++++++++ Main.py | 12 ++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Gui.py b/Gui.py index 4cc5b106..6433c79f 100755 --- a/Gui.py +++ b/Gui.py @@ -24,6 +24,13 @@ from source.classes.BabelFish import BabelFish from source.classes.Empty import Empty +def check_python_version(): + import sys + version = sys.version_info + if version.major < 3 or version.minor < 7: + messagebox.showinfo("Door Shuffle " + ESVersion, 'Door Rando may have issues with python versions earlier than 3.7. Detected version: %s' % sys.version) + + def guiMain(args=None): # Save settings to file def save_settings(args): @@ -188,6 +195,8 @@ def guiMain(args=None): # load adjust settings into options loadadjustargs(self, self.settings) + check_python_version() + # run main window mainWindow.mainloop() diff --git a/Main.py b/Main.py index eb8380f3..5a2e4370 100644 --- a/Main.py +++ b/Main.py @@ -34,7 +34,15 @@ class EnemizerError(RuntimeError): pass +def check_python_version(): + import sys + version = sys.version_info + if version.major < 3 or version.minor < 7: + logging.warning('Door Rando may have issues with python versions earlier than 3.7. Detected version: %s', sys.version) + + def main(args, seed=None, fish=None): + check_python_version() if args.outputpath: os.makedirs(args.outputpath, exist_ok=True) output_path.cached_path = args.outputpath @@ -257,11 +265,11 @@ def main(args, seed=None, fish=None): rom = JsonRom() if args.jsonout or use_enemizer else LocalRom(args.rom) if use_enemizer and (args.enemizercli or not args.jsonout): - base_patch = LocalRom(args.rom) # update base2current.json (side effect) + local_rom = LocalRom(args.rom) # update base2current.json (side effect) 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): - patch_enemizer(world, player, rom, args.rom, args.enemizercli, sprite_random_on_hit) + patch_enemizer(world, player, rom, local_rom, args.enemizercli, sprite_random_on_hit) enemized = True if not args.jsonout: rom = LocalRom.fromJsonRom(rom, args.rom, 0x400000) From 4d8bfe0e22791b17aeb7e428e76eac8a35fdc535 Mon Sep 17 00:00:00 2001 From: compiling <8335770+compiling@users.noreply.github.com> Date: Sun, 25 Jul 2021 18:15:51 +1000 Subject: [PATCH 18/30] Check for headered roms before passing to enemizer. --- Rom.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/Rom.py b/Rom.py index 5c61e5c2..bde37484 100644 --- a/Rom.py +++ b/Rom.py @@ -86,10 +86,12 @@ class LocalRom(object): self.name = name self.hash = hash self.orig_buffer = None + self.file = file + self.has_smc_header = False if not os.path.isfile(file): raise RuntimeError("Could not find valid local base rom for patching at expected path %s." % file) with open(file, 'rb') as stream: - self.buffer = read_rom(stream) + self.buffer, self.has_smc_header = read_rom(stream) if patch: self.patch_base_rom() self.orig_buffer = self.buffer.copy() @@ -187,12 +189,21 @@ def write_int32s(rom, startaddress, values): def read_rom(stream): "Reads rom into bytearray and strips off any smc header" buffer = bytearray(stream.read()) + has_smc_header = False if len(buffer)%0x400 == 0x200: buffer = buffer[0x200:] - return buffer + has_smc_header = True + return buffer, has_smc_header -def patch_enemizer(world, player, rom, baserom_path, enemizercli, random_sprite_on_hit): - baserom_path = os.path.abspath(baserom_path) +def patch_enemizer(world, player, rom, local_rom, enemizercli, random_sprite_on_hit): + baserom_path = os.path.abspath(local_rom.file) + unheadered_path = None + if local_rom.has_smc_header: + headered_path = baserom_path + unheadered_path = baserom_path = os.path.abspath(output_path('unheadered_rom.sfc')) + with open(headered_path, 'rb') as headered: + with open(baserom_path, 'wb') as unheadered: + unheadered.write(headered.read()[0x200:]) basepatch_path = os.path.abspath(local_path(os.path.join("data","base2current.json"))) enemizer_basepatch_path = os.path.join(os.path.dirname(enemizercli), "enemizerBasePatch.json") randopatch_path = os.path.abspath(output_path('enemizer_randopatch.json')) @@ -336,6 +347,12 @@ def patch_enemizer(world, player, rom, baserom_path, enemizercli, random_sprite_ rom.write_bytes(0x307000 + (i * 0x8000), sprite.palette) rom.write_bytes(0x307078 + (i * 0x8000), sprite.glove_palette) + if local_rom.has_smc_header: + try: + os.remove(unheadered_path) + except OSError: + pass + try: os.remove(randopatch_path) except OSError: From dc950112d9a89e35260920cddc0324112b1a124f Mon Sep 17 00:00:00 2001 From: compiling <8335770+compiling@users.noreply.github.com> Date: Sun, 25 Jul 2021 18:17:10 +1000 Subject: [PATCH 19/30] Fix Aga rule for standard - should be Zelda + normal requirements. --- Rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rules.py b/Rules.py index 3762b9bb..c9dc03f9 100644 --- a/Rules.py +++ b/Rules.py @@ -1149,7 +1149,7 @@ def standard_rules(world, player): set_rule(entrance, lambda state: state.has('Zelda Delivered', player)) set_rule(world.get_entrance('Sanctuary Exit', player), lambda state: state.has('Zelda Delivered', player)) # zelda should be saved before agahnim is in play - set_rule(world.get_location('Agahnim 1', player), lambda state: state.has('Zelda Delivered', player)) + add_rule(world.get_location('Agahnim 1', player), lambda state: state.has('Zelda Delivered', player)) # too restrictive for crossed? def uncle_item_rule(item): From 4d90ca9181267828dbe003686525e798bd126372 Mon Sep 17 00:00:00 2001 From: compiling <8335770+compiling@users.noreply.github.com> Date: Sun, 25 Jul 2021 19:48:07 +1000 Subject: [PATCH 20/30] Add python version warning to the translation file. --- Gui.py | 6 +++--- Main.py | 4 +++- resources/app/cli/lang/en.json | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Gui.py b/Gui.py index 6433c79f..55defa7a 100755 --- a/Gui.py +++ b/Gui.py @@ -24,11 +24,11 @@ from source.classes.BabelFish import BabelFish from source.classes.Empty import Empty -def check_python_version(): +def check_python_version(fish): import sys version = sys.version_info if version.major < 3 or version.minor < 7: - messagebox.showinfo("Door Shuffle " + ESVersion, 'Door Rando may have issues with python versions earlier than 3.7. Detected version: %s' % sys.version) + messagebox.showinfo("Door Shuffle " + ESVersion, fish.translate("cli","cli","old.python.version") % sys.version) def guiMain(args=None): @@ -195,7 +195,7 @@ def guiMain(args=None): # load adjust settings into options loadadjustargs(self, self.settings) - check_python_version() + check_python_version(self.fish) # run main window mainWindow.mainloop() diff --git a/Main.py b/Main.py index 5a2e4370..665196fc 100644 --- a/Main.py +++ b/Main.py @@ -29,6 +29,8 @@ from Utils import output_path, parse_player_names __version__ = '0.4.0.11u' +from source.classes.BabelFish import BabelFish + class EnemizerError(RuntimeError): pass @@ -38,7 +40,7 @@ def check_python_version(): import sys version = sys.version_info if version.major < 3 or version.minor < 7: - logging.warning('Door Rando may have issues with python versions earlier than 3.7. Detected version: %s', sys.version) + logging.warning(BabelFish().translate("cli","cli","old.python.version"), sys.version) def main(args, seed=None, fish=None): diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index 0ff910a9..d2be5eb0 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -52,7 +52,8 @@ "enemizer.nothing.applied": "No Enemizer options will be applied until this is resolved.", "building.collection.spheres": "Building up collection spheres", "building.calculating.spheres": "Calculated sphere %i, containing %i of %i progress items.", - "building.final.spheres": "Calculated final sphere %i, containing %i of %i progress items." + "building.final.spheres": "Calculated final sphere %i, containing %i of %i progress items.", + "old.python.version": "Door Rando may have issues with python versions earlier than 3.7. Detected version: %s" }, "help": { "lang": [ "App Language, if available, defaults to English" ], From e5e90fc805eba03f61d0694081e7432f51b32829 Mon Sep 17 00:00:00 2001 From: StructuralMike <66819228+StructuralMike@users.noreply.github.com> Date: Mon, 26 Jul 2021 11:09:24 +0200 Subject: [PATCH 21/30] Remove default bomb upgrades from shop --- ItemList.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ItemList.py b/ItemList.py index a1d31968..5ad981bf 100644 --- a/ItemList.py +++ b/ItemList.py @@ -523,6 +523,17 @@ def set_up_shops(world, player): rss.locked = True cap_shop = world.get_region('Capacity Upgrade', player).shop cap_shop.inventory[1] = None # remove arrow capacity upgrades in retro + if world.bomblogic[player]: + if world.shopsanity[player]: + removals = [item for item in world.itempool if item.name == 'Bomb Upgrade (+5)' and item.player == player] + for i in removals: + print(i) + for remove in removals: + world.itempool.remove(remove) + world.itempool.append(ItemFactory('Rupees (50)', player)) # replace the bomb upgrade + else: + cap_shop = world.get_region('Capacity Upgrade', player).shop + cap_shop.inventory[0] = cap_shop.inventory[1] # remove bomb capacity upgrades in bomblogic def customize_shops(world, player): @@ -567,7 +578,7 @@ def customize_shops(world, player): if not found_bomb_upgrade and len(possible_replacements) > 0: choices = [] for shop, idx, loc, item in possible_replacements: - if item.name in ['Bombs (3)', 'Bombs (10)']: + if item.name in ['Bombs (3)', 'Bombs (10)'] and not world.bomblogic[player]: choices.append((shop, idx, loc, item)) if len(choices) > 0: shop, idx, loc, item = random.choice(choices) From 9247c547d3ff00e237639fbca6810aa50890f954 Mon Sep 17 00:00:00 2001 From: StructuralMike <66819228+StructuralMike@users.noreply.github.com> Date: Mon, 26 Jul 2021 11:12:47 +0200 Subject: [PATCH 22/30] Update ItemList.py --- ItemList.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ItemList.py b/ItemList.py index 5ad981bf..f3853e4f 100644 --- a/ItemList.py +++ b/ItemList.py @@ -526,8 +526,6 @@ def set_up_shops(world, player): if world.bomblogic[player]: if world.shopsanity[player]: removals = [item for item in world.itempool if item.name == 'Bomb Upgrade (+5)' and item.player == player] - for i in removals: - print(i) for remove in removals: world.itempool.remove(remove) world.itempool.append(ItemFactory('Rupees (50)', player)) # replace the bomb upgrade From 322273673b8a56610f685c9d229137526c474b11 Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 26 Jul 2021 12:19:45 -0600 Subject: [PATCH 23/30] stage unstable for next release cycle --- Main.py | 2 +- RELEASENOTES.md | 130 ++---------------------------------------------- 2 files changed, 5 insertions(+), 127 deletions(-) diff --git a/Main.py b/Main.py index 8909301a..aea113c0 100644 --- a/Main.py +++ b/Main.py @@ -28,7 +28,7 @@ from Fill import sell_potions, sell_keys, balance_multiworld_progression, balanc from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops from Utils import output_path, parse_player_names -__version__ = '0.4.0.12u' +__version__ = '0.5.0.0-u' class EnemizerError(RuntimeError): diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 0ccceb80..2eb25d4a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,116 +1,11 @@ # New Features -## Maiden Hint for Theives Town Attic - -In crossed dungeon mode, if you bring the maiden to the boss room when the attic is not bombed (and thus no light in the room), she mentions the dungeon where you can find the cracked floor. - -## Shuffle Links House - -Links house can now be shuffled in different ER settings. It will be limited to the Light World (or Dark World in inverted) if Crossed or Insanity shuffle is not one. It it also limited if door shuffle settings allow the Sanctuary to be in the dark world. (This is prevent having no Light World spawn points in Open modes) This setting is ignored by standard mode. THe CLI parameter is --shufflelinks - -## OWG Glitch Logic - -Thanks to qadan, cheuer, & compiling - -## Pseudo Boots - -Thanks to Bonta. You can now start with pseudo boots that let you move fast, but have no other logical uses (bonking open things, hovering, etc) - -## Pendant/Crystal Indicator - -For accessibility, you now get a C or P indicator to the left of the magic bar on the HUD when instead a Crystal or Pendant. Requires ownership of the map of that dungeon for display. Thanks to kan. +None yet # Bug Fixes and Notes. -* 0.4.0.12 - * ER Inverted fix for HC Ledge, and Aga Tower choosing Links House incorrectly - * Credits again - hopefully for good - * Incorporated music fixes for now (may revisit later) - * Secure random re-incorporated -* 0.4.0.11 - * Some minor base rom fixes - * Improved distribution of bombable/dashable doors -* 0.4.0.10 - * Renamed to pseudoboots - * Some release note updates -* 0.4.0.9 - * Fixes for stats and P/C indicator (thanks Kara) - * Swamp lobby fixes (thanks Catobat) - * Fix for --hints flag on CLI -* 0.4.0.8 - * Ganon jokes added for when silvers aren't available - * Some text updated (Blind jokes, uncle text) - * Fixed some enemizer Mystery settings - * Added a setting that's random enemy shuffle without Unkillable Thieves possible - * Fixed shop spoiler when money balancing/multiworld balancing - * Fixed a problem with insanity - * Fixed an issue with the credit stats specific to DR (e.g. collection rate total) - * More helpful error message when bps is missing? - * Minor generation issues involving enemizer and the link sprite - * Baserom updates (from Bonta, kan, qwertymodo, ardnaxelark) - * Boss icon on dungeon map (if you have a compass) - * Progressive bow sprite replacement - * Quickswap - consecutive special swaps - * Bonk Counter - * One mind - * MSU fix - * Chest turn tracking (not yet in credits) - * Damaged and magic stats in credits (gt bk removed) - * Fix for infinite bombs - * Pseudo boots option - * Always allowed medallions for swordless (no option yet) -* 0.4.0.7 - * Reduce flashing option added - * Sprite author credit added - * Ranged Crystal switch rules tweaked - * Baserom update: includes Credits Speedup, reduced flashing option, msu resume (but turned off by default) - * Create link sprite's zspr from local ROM and no longer attempts to download it from website - * Some minor bug fixes -* 0.4.0.6 - * Hints now default to off - * The maiden gives you a hint to the attic if you bring her to the unlit boss room - * Beemizer support and fix for shopsanity - * Capacity upgrades removed in hard/expert item difficulties - * Swamp Hub added to lobby shuffle with ugly cave entrance. - * TR Lava Escape added to lobby shuffle. - * Hyrule Main Lobby and Sanctuary can now have a more visible outside exit, and rugs modified to be fully clipped. -* 0.4.0.5 - * Insanity - less restrictions on exiting (all modes) - * Fix for simple bosses shuffle - * Fix for boss shuffle from Mystery.py - * Minor msu fade out bug (thanks codemann8) - * Other bug fixes (thanks Catobat) -* 0.4.0.4 - * Added --shufflelinks option - * Moved spawning as a bunny indoors to experimental - * Baserom bug fixes -* 0.4.0.3 - * Fixed a bug where Sanctuary could be chosen as a lobby for a DW dungeon in non-crossed ER modes -* 0.4.0.2 - * Fixed a bug where Defeat Ganon is not possible - * Fixed the item counter total - * Fixed the bunny state when starting out in Sanc in a dark world dungeon -* 0.4.0.1 - * Moved stonewall pre-opening to not happen in experimental - * Updated baserom - * Boss RNG perseved between files - * Vanilla prize pack fix - * Starting equipment fix - * Post-Aga world state option - * Code optimzation - * Bottle quickswap via double shoulder - * Credits update - * Accessibility option - * Sewer map/compass fix - * Fixed a standard bug where the exits to the ledge would be unavailable if the pyramid was pre-opened - * DR ASM optimization - * Removed Archery Game from Take-Any caves in inverted - * Fixed a problem with new YAML parser -* 0.4.0.0 - * Mystery yaml parser updated to a package maintained version (Thanks StructuralMike) - * Bomb-logic and extend crystal switch logic (Thanks StructuralMike) - * Fixed logic for moved locations in playthrough (Thanks compiling) - * OWG Glitch logic added +* 0.5.0.0 + * None yet # Known Issues @@ -118,21 +13,4 @@ For accessibility, you now get a C or P indicator to the left of the magic bar o * Hints for items in shops can be misleading (ER) * Forfeit in Multiworld not granting all shop items * Potential keylocks in multi-entrance dungeons -* Incorrect vanilla key logic for Mire - -## Other Notes - -### Triforce Hunt Options - -Thanks to deathFouton! - ---triforce_pool and --triforce_goal added to the CLI. - -Also, to the Mystery.py he added the following options: -* triforce_goal_min -* triforce_goal_max -* triforce_pool_min -* triforce_pool_max -* triforce_min_difference - -See the example yaml file for demonstrated usage. \ No newline at end of file +* Incorrect vanilla key logic for Mire \ No newline at end of file From 066d239b70de5137ca5a556352571db592e027d3 Mon Sep 17 00:00:00 2001 From: aerinon Date: Tue, 27 Jul 2021 08:58:31 -0600 Subject: [PATCH 24/30] Boss music fix --- RELEASENOTES.md | 5 ++++- Rom.py | 2 +- data/base2current.bps | Bin 136267 -> 136271 bytes 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 2eb25d4a..95d116ef 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -5,7 +5,10 @@ None yet # Bug Fixes and Notes. * 0.5.0.0 - * None yet + * Handles headered roms for enemizer (Thanks compiling) + * Warning added for earlier version of pythong (Thanks compiling) + * Minor logic issue for defeating Aga in standard (Thanks compiling) + * Fix for boss music in non-DR modes (Thanks codemann8) # Known Issues diff --git a/Rom.py b/Rom.py index fcc9d426..dd4e287e 100644 --- a/Rom.py +++ b/Rom.py @@ -30,7 +30,7 @@ from EntranceShuffle import door_addresses, exit_ids JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '9c2878d1035bb3889784906a55a92a26' +RANDOMIZERBASEHASH = '988f1546b14d8f2e6ee30b9de44882da' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index a904b07d50f9fadac099414d033b0c27b309563b..5f41171067dccc266f98a3c0b2daee5a07a03f06 100644 GIT binary patch delta 5253 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 delta 5364 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 q>=Zx2ly7Ye>5S6|F From c182e73b778ae198a690cf3cd087e779e0e6b78f Mon Sep 17 00:00:00 2001 From: aerinon Date: Tue, 27 Jul 2021 11:33:10 -0600 Subject: [PATCH 25/30] Mystery can apply reduce_flashing --- Mystery.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Mystery.py b/Mystery.py index d3e3bddf..1ab4a90b 100644 --- a/Mystery.py +++ b/Mystery.py @@ -226,6 +226,7 @@ def roll_settings(weights): ret.sprite = get_choice('sprite', romweights) ret.disablemusic = get_choice('disablemusic', romweights) == 'on' ret.quickswap = get_choice('quickswap', romweights) == 'on' + ret.reduce_flashing = get_choice('reduce_flashing', romweights) == 'on' ret.fastmenu = get_choice('menuspeed', romweights) ret.heartcolor = get_choice('heartcolor', romweights) ret.heartbeep = get_choice('heartbeep', romweights) From ce24017297bc48daa12546aa56d238aae97ac474 Mon Sep 17 00:00:00 2001 From: aerinon Date: Tue, 27 Jul 2021 13:13:18 -0600 Subject: [PATCH 26/30] typo --- RELEASENOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 95d116ef..2ac7dbdc 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -6,7 +6,7 @@ None yet * 0.5.0.0 * Handles headered roms for enemizer (Thanks compiling) - * Warning added for earlier version of pythong (Thanks compiling) + * Warning added for earlier version of python (Thanks compiling) * Minor logic issue for defeating Aga in standard (Thanks compiling) * Fix for boss music in non-DR modes (Thanks codemann8) From d70f2ee355b47c047688be9b4977d2330c34d400 Mon Sep 17 00:00:00 2001 From: aerinon Date: Wed, 28 Jul 2021 15:21:51 -0600 Subject: [PATCH 27/30] Small changes for bomblogic --- ItemList.py | 7 +++++-- Items.py | 2 +- Main.py | 2 +- RELEASENOTES.md | 9 +++++++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/ItemList.py b/ItemList.py index f3853e4f..57566418 100644 --- a/ItemList.py +++ b/ItemList.py @@ -524,6 +524,9 @@ def set_up_shops(world, player): cap_shop = world.get_region('Capacity Upgrade', player).shop cap_shop.inventory[1] = None # remove arrow capacity upgrades in retro if world.bomblogic[player]: + for item in world.itempool: + if item.name == 'Bomb Upgrade (+10)' and item.player == player: + item.advancement = True if world.shopsanity[player]: removals = [item for item in world.itempool if item.name == 'Bomb Upgrade (+5)' and item.player == player] for remove in removals: @@ -573,10 +576,10 @@ def customize_shops(world, player): shop.shopkeeper_config = shopkeeper # handle capacity upgrades - randomly choose a bomb bunch or arrow bunch to become capacity upgrades if world.difficulty[player] == 'normal': - if not found_bomb_upgrade and len(possible_replacements) > 0: + if not found_bomb_upgrade and len(possible_replacements) > 0 and not world.bomblogic[player]: choices = [] for shop, idx, loc, item in possible_replacements: - if item.name in ['Bombs (3)', 'Bombs (10)'] and not world.bomblogic[player]: + if item.name in ['Bombs (3)', 'Bombs (10)']: choices.append((shop, idx, loc, item)) if len(choices) > 0: shop, idx, loc, item = random.choice(choices) diff --git a/Items.py b/Items.py index 279cc33d..808a0740 100644 --- a/Items.py +++ b/Items.py @@ -81,7 +81,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche 'Single Bomb': (False, False, None, 0x27, 5, 'I make things\ngo BOOM! But\njust once.', 'and the explosion', 'the bomb-holding kid', 'firecracker for sale', 'blend fungus into bomb', '\'splosion boy explodes again', 'a bomb'), 'Bombs (3)': (False, False, None, 0x28, 15, 'I make things\ngo triple\nBOOM!!!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'three bombs'), 'Bombs (10)': (False, False, None, 0x31, 50, 'I make things\ngo BOOM! Ten\ntimes!', 'and the explosions', 'the bomb-holding kid', 'firecrackers for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'ten bombs'), - 'Bomb Upgrade (+10)': (True, False, None, 0x52, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), + 'Bomb Upgrade (+10)': (False, False, None, 0x52, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), 'Bomb Upgrade (+5)': (False, False, None, 0x51, 100, 'increase bomb\nstorage, low\nlow price', 'and the bomb bag', 'boom-enlarging kid', 'bomb boost for sale', 'the shroom goes boom', 'upgrade boy explodes more again', 'bomb capacity'), 'Blue Mail': (False, True, None, 0x22, 50, 'Now you\'re a\nblue elf!', 'and the banana hat', 'the protected kid', 'banana hat for sale', 'the clothing store', 'tailor boy banana hatted again', 'the blue mail'), 'Red Mail': (False, True, None, 0x23, 100, 'Now you\'re a\nred elf!', 'and the eggplant hat', 'well-protected kid', 'purple hat for sale', 'the nice clothing store', 'tailor boy fears nothing again', 'the red mail'), diff --git a/Main.py b/Main.py index 0a8519b6..75831f5c 100644 --- a/Main.py +++ b/Main.py @@ -28,7 +28,7 @@ from Fill import sell_potions, sell_keys, balance_multiworld_progression, balanc from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops from Utils import output_path, parse_player_names -__version__ = '0.5.0.0-u' +__version__ = '0.5.0.1-u' from source.classes.BabelFish import BabelFish diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 2ac7dbdc..c0fae696 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,9 +1,14 @@ # New Features -None yet +Bomb Logic added as an option. This removes your ability to use bombs until you find a "bomb bag", a +10 Bomb Capacity item. It is accounted for in the logic, so you aren't expected to get items behind bomb walls until you have found the bomb capacity item. The upgrades are removed from the upgrade fairy as well. + +``` +--bomblogic +``` # Bug Fixes and Notes. - +* 0.5.0.1 + * --bomblogic option added * 0.5.0.0 * Handles headered roms for enemizer (Thanks compiling) * Warning added for earlier version of python (Thanks compiling) From 4c15c193f42e6156e66e5558ef8daf68210754e3 Mon Sep 17 00:00:00 2001 From: StructuralMike <66819228+StructuralMike@users.noreply.github.com> Date: Thu, 29 Jul 2021 15:27:49 +0200 Subject: [PATCH 28/30] Set bomb upgrades as advancement before beemizer Beemizer can replace bomb upgrades in bomblogic unless they're tagged as advancement earlier --- ItemList.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ItemList.py b/ItemList.py index 57566418..9128436a 100644 --- a/ItemList.py +++ b/ItemList.py @@ -301,6 +301,11 @@ def generate_itempool(world, player): world.get_location(location, player).event = True world.get_location(location, player).locked = True + if world.bomblogic[player]: + for item in world.itempool: + if item.name == 'Bomb Upgrade (+10)' and item.player == player: + item.advancement = True + if world.shopsanity[player]: for shop in world.shops[player]: if shop.region.name in shop_to_location_table: @@ -524,9 +529,6 @@ def set_up_shops(world, player): cap_shop = world.get_region('Capacity Upgrade', player).shop cap_shop.inventory[1] = None # remove arrow capacity upgrades in retro if world.bomblogic[player]: - for item in world.itempool: - if item.name == 'Bomb Upgrade (+10)' and item.player == player: - item.advancement = True if world.shopsanity[player]: removals = [item for item in world.itempool if item.name == 'Bomb Upgrade (+5)' and item.player == player] for remove in removals: From c06477c0f20fb00fdbd80b893e10ffb7b6a3ad42 Mon Sep 17 00:00:00 2001 From: StructuralMike <66819228+StructuralMike@users.noreply.github.com> Date: Thu, 29 Jul 2021 15:51:56 +0200 Subject: [PATCH 29/30] Update ItemList.py --- ItemList.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ItemList.py b/ItemList.py index 9128436a..e79392b8 100644 --- a/ItemList.py +++ b/ItemList.py @@ -301,11 +301,6 @@ def generate_itempool(world, player): world.get_location(location, player).event = True world.get_location(location, player).locked = True - if world.bomblogic[player]: - for item in world.itempool: - if item.name == 'Bomb Upgrade (+10)' and item.player == player: - item.advancement = True - if world.shopsanity[player]: for shop in world.shops[player]: if shop.region.name in shop_to_location_table: @@ -323,6 +318,11 @@ def generate_itempool(world, player): p_item = next(item for item in items if item.name == potion and item.player == player) p_item.priority = True # don't beemize one of each potion + if world.bomblogic[player]: + for item in items: + if item.name == 'Bomb Upgrade (+10)' and item.player == player: + item.advancement = True + world.lamps_needed_for_dark_rooms = lamps_needed_for_dark_rooms if clock_mode is not None: From bcaee735a2835ca2d3ef3b99a24d29ae9b40be2c Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 2 Aug 2021 15:24:13 -0600 Subject: [PATCH 30/30] SFX shuffle added --- Main.py | 2 +- RELEASENOTES.md | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Main.py b/Main.py index e44c804e..df4426e8 100644 --- a/Main.py +++ b/Main.py @@ -28,7 +28,7 @@ from Fill import sell_potions, sell_keys, balance_multiworld_progression, balanc from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops from Utils import output_path, parse_player_names -__version__ = '0.5.0.1-u' +__version__ = '0.5.0.2-u' from source.classes.BabelFish import BabelFish diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c0fae696..b6be375d 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,12 +1,22 @@ # New Features -Bomb Logic added as an option. This removes your ability to use bombs until you find a "bomb bag", a +10 Bomb Capacity item. It is accounted for in the logic, so you aren't expected to get items behind bomb walls until you have found the bomb capacity item. The upgrades are removed from the upgrade fairy as well. +## Shuffle SFX + +Shuffles a large portion of the sounds effects. Can be used with the adjuster. + +CLI: ```--shuffle_sfx``` -``` ---bomblogic -``` +## Bomb Logic + +When enabling this option, you do not start with bomb capacity but rather you must find 1 of 2 bomb bags. (They are represented by the +10 capacity item.) Bomb capacity upgrades are otherwise unavailable. + +CLI: ```--bomblogic``` + # Bug Fixes and Notes. + +* 0.5.0.2 + * --shuffle_sfx option added * 0.5.0.1 * --bomblogic option added * 0.5.0.0