diff --git a/CHANGELOG.md b/CHANGELOG.md index 39dc836e..a833eaec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.6.0.6 +- Added ability to change GT entry cutscene GFX thru customizer +- Chicken as a standing item is no longer a star gfx +- Fix issue in DR with music silence in pre-Aga room +- Other various music fixes +- Fixed issue with Mystery subweights not correctly evaluating boolean settings + ## 0.6.0.5 - Emergency fix for map/key totals in non-DR diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 8cc25ac5..b21edecc 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -8,7 +8,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.6.0.5' +version_number = '0.6.0.6' # branch indicator is intentionally different across branches version_branch = '' diff --git a/Rom.py b/Rom.py index 7401ce94..d89de2a3 100644 --- a/Rom.py +++ b/Rom.py @@ -43,7 +43,7 @@ from source.enemizer.Enemizer import write_enemy_shuffle_settings JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '94672b7a306b32c8a1d9e64f0e6a9be0' +RANDOMIZERBASEHASH = 'b8c930c1922fb15018c76be902cc15d9' class JsonRom(object): @@ -1089,8 +1089,8 @@ def patch_rom(world, rom, player, team, is_mystery=False): 0x51, 0x00 if world.bombbag[player] else 0x06, 0x31 if world.bombbag[player] else 0x52, 0xFF, # 6 +5 bomb upgrades -> +10 bomb upgrade. If bombbag -> turns into Bombs (10) 0x53, 0x06, 0x54, 0xFF, # 6 +5 arrow upgrades -> +10 arrow upgrade 0x58, 0x01, 0x36 if world.bow_mode[player].startswith('retro') else 0x43, 0xFF, # silver arrows -> single arrow (red 20 in retro mode) - 0x3E, difficulty.boss_heart_container_limit, 0x47, 0xff, # boss heart -> green 20 - 0x17, difficulty.heart_piece_limit, 0x47, 0xff, # piece of heart -> green 20 + 0x3E, difficulty.boss_heart_container_limit, GREEN_TWENTY_RUPEES, 0xff, # boss heart -> green 20 + 0x17, difficulty.heart_piece_limit, GREEN_TWENTY_RUPEES, 0xff, # piece of heart -> green 20 0xFF, 0xFF, 0xFF, 0xFF, # end of table sentinel ]) @@ -1642,6 +1642,26 @@ def patch_rom(world, rom, player, team, is_mystery=False): write_enemizer_tweaks(rom, world, player) write_strings(rom, world, player, team) + # gt entry + if world.customizer: + gtentry = world.customizer.get_gtentry() + if gtentry and player in gtentry: + gtentry = gtentry[player] + if 'cutscene_gfx' in gtentry: + gfx = gtentry['cutscene_gfx'] + if type(gfx) is str: + from Tables import item_gfx_table + if gfx.lower() == 'random': + gfx = random.choice(list(item_gfx_table.keys())) + if gfx in item_gfx_table: + write_int16(rom, snes_to_pc(0x3081AA), item_gfx_table[gfx][1] + (0x8000 if not item_gfx_table[gfx][0] else 0)) + rom.write_byte(snes_to_pc(0x3081AC), item_gfx_table[gfx][2]) + else: + logging.getLogger('').warning('Invalid name "%s" in customized GT entry cutscene gfx', gfx) + else: + write_int16(rom, snes_to_pc(0x3081AA), gfx[0]) + rom.write_byte(snes_to_pc(0x3081AC), gfx[1]) + # write initial sram rom.write_initial_sram() diff --git a/Tables.py b/Tables.py index 52f96488..33e1e230 100644 --- a/Tables.py +++ b/Tables.py @@ -146,3 +146,102 @@ bonk_prize_lookup = { 'Arrows (10)': (0xe2, 0, None), 'Fairy': (0xe3, 15, None) } + +# item name: (custom gfx, address offset, palette) +# decompressed gfx loaded at $7F8000 +# custom gfx loaded at $228000 +item_gfx_table = { + 'Green Rupees (20)': (False, 0x0000, 0x04), + 'Pegasus Boots': (False, 0x0040, 0x01), + 'Psuedoboots': (False, 0x0040, 0x02), + 'Blue Pendant': (False, 0x0080, 0x02), + 'Red Pendant': (False, 0x0080, 0x01), + 'Warp Tile': (False, 0x00C0, 0x04), + 'Open Chest': (False, 0x0100, 0x02), + 'Chicken': (False, 0x0140, 0x04), + 'Duck': (False, 0x0180, 0x01), + 'Chest': (False, 0x0400, 0x02), + 'Frog': (False, 0x0440, 0x04), + 'Kiki (Head)': (False, 0x0480, 0x04), + 'Purple Chest': (False, 0x0500, 0x04), + 'Super Bomb': (False, 0x0540, 0x04), + 'Blacksmith': (False, 0x0580, 0x04), + 'Bug Net': (False, 0x0860, 0x01), + 'Crystal': (False, 0x08A0, 0x06), + 'Silver Arrows': (False, 0x08E0, 0x01), + 'Bow': (False, 0x0920, 0x02), + 'Bottle (Fairy)': (False, 0x0960, 0x02), + 'Bottle (Bee)': (False, 0x09A0, 0x02), + 'Piece of Heart': (False, 0x0C00, 0x01), + 'Ocarina': (False, 0x0C40, 0x02), + 'Mirror Shield': (False, 0x0C80, 0x04), + 'Rupees (100)': (False, 0x0D20, 0x04), + 'Rupees (50)': (False, 0x0D60, 0x04), + 'Rupees (300)': (False, 0x0DA0, 0x04), + 'Flippers': (False, 0x1000, 0x02), + 'Mirror': (False, 0x1040, 0x02), + 'Bomb': (False, 0x1080, 0x02), + 'Lamp': (False, 0x10C0, 0x01), + 'Psuedolamp': (False, 0x10C0, 0x02), + 'Magic Cape': (False, 0x1100, 0x01), + 'Compass': (False, 0x1140, 0x02), + 'Moon Pearl': (False, 0x1180, 0x01), + 'Ether': (False, 0x1400, 0x04), + 'Bombos': (False, 0x1440, 0x04), + 'Quake': (False, 0x1480, 0x04), + 'Bottle': (False, 0x14C0, 0x01), + 'Bottle (Red Potion)': (False, 0x1500, 0x01), + 'Bottle (Green Potion)': (False, 0x1500, 0x04), + 'Bottle (Blue Potion)': (False, 0x1500, 0x02), + 'Mushroom': (False, 0x1540, 0x04), + 'Map': (False, 0x1580, 0x04), + 'Big Key': (False, 0x15C0, 0x04), + 'Bombs (3)': (False, 0x1840, 0x02), + 'Arrows (10)': (False, 0x1880, 0x02), + 'Heart Container': (False, 0x18C0, 0x01), + 'Green Mail': (False, 0x1900, 0x04), + 'Blue Mail': (False, 0x1900, 0x02), + 'Red Mail': (False, 0x1900, 0x01), + 'Fire Sheild': (False, 0x1980, 0x04), + 'Blue Shield': (False, 0x19C0, 0x02), + 'Magic Powder': (False, 0x1CC0, 0x02), + 'Bombs (10)': (False, 0x1D00, 0x02), + 'Power Glove': (False, 0x1D40, 0x01), + 'Titans Mitts': (False, 0x1D40, 0x04), + 'Book of Mudora': (False, 0x1D80, 0x04), + 'Maiden (Head)': (False, 0x2000, 0x04), + 'Zelda (Head)': (False, 0x2080, 0x04), + 'Old Man (Head)': (False, 0x2140, 0x04), + 'Locksmith (Head)': (False, 0x2180, 0x04), + 'Fire': (False, 0x25C0, 0x04), + 'Apples': (False, 0x30A0, 0x04), + 'Fairy': (False, 0x3140, 0x01), + 'Whirlpool': (False, 0x31C0, 0x01), + + 'Triforce': (True, 0x0060, 0x04), + 'Fighter Sword': (True, 0x00A0, 0x02), + 'Master Sword': (True, 0x00E0, 0x02), + 'Tempered Sword': (True, 0x0120, 0x01), + 'Golden Sword': (True, 0x0160, 0x04), + 'Half Magic': (True, 0x01A0, 0x04), + 'Quarter Magic': (True, 0x01E0, 0x04), + 'Bomb Upgrade (+5)': (True, 0x0420, 0x04), + 'Bomb Upgrade (+10)': (True, 0x0460, 0x04), + 'Bomb Upgrade (50)': (True, 0x04A0, 0x04), + 'Bombbag': (True, 0x04E0, 0x02), + 'Arrow Upgrade (+5)': (True, 0x0520, 0x02), + 'Arrow Upgrade (+10)': (True, 0x0560, 0x02), + 'Arrows (70)': (True, 0x05A0, 0x02), + 'Silver Arrows (Ag)': (True, 0x05E0, 0x01), + 'Green Pendant': (True, 0x0820, 0x04), + 'Sword and Shield': (True, 0x0860, 0x02), + 'Green Potion': (True, 0x08A0, 0x04), + 'Blue Potion': (True, 0x08E0, 0x02), + 'Red Potion': (True, 0x0920, 0x01), + 'Bee Trap': (True, 0x0960, 0x02), + 'Red Crystal': (True, 0x0C60, 0x01), + 'Egg': (True, 0x1020, 0x02), + 'Master Key': (True, 0x1060, 0x02), + 'Lumberjack (Head)': (True, 0x11A0, 0x02), + 'Power Star': (True, 0x11E0, 0x04), +} diff --git a/data/base2current.bps b/data/base2current.bps index 1d855761..a4f36a67 100644 Binary files a/data/base2current.bps and b/data/base2current.bps differ diff --git a/docs/Customizer.md b/docs/Customizer.md index c184aae3..0113a501 100644 --- a/docs/Customizer.md +++ b/docs/Customizer.md @@ -334,7 +334,7 @@ drops: Prize packs expect a list of eight items each (anything not specified will be whatever randomization would have normally occurred). The special drops expect a single item. Packs 1 through 7 are supported. Prize pack 0 is not customizable. -## prices +### prices This must be defined by player. You may have the prices of items in shops defined using the following @@ -347,4 +347,28 @@ prices: Dark Death Mountain Shop - Middle: 150 Dark Death Mountain Shop - Right: 300 Dark Lake Hylia Shop - Left: 200 -``` \ No newline at end of file +``` + +### gt_entry + +This must be defined by player. This is where you are able to customize aspects of GT entry + +#### cutscene_gfx + +This is where you can define custom GFX to be used in the GT entry cutscene. For convenience, there are a number of pre-defined names that can be used to indicate already known GFX values built into the ROM. There are too many to list, but a full list can be found in `item_gfx_table` in `Tables.py`. You can also use `Random` and it will take a random one from the aforementioned table. + +``` +gt_entry: + 1: + cutscene_gfx: Mirror Shield +``` + +Alternatively, you may also supply a custom address and palette ID, respectively, if you are injecting your own personal custom GFX into the ROM. + +``` +gt_entry: + 1: + cutscene_gfx: + - 0x8140 + - 0x04 +``` diff --git a/source/classes/CustomSettings.py b/source/classes/CustomSettings.py index 539b9c06..0b421fca 100644 --- a/source/classes/CustomSettings.py +++ b/source/classes/CustomSettings.py @@ -298,6 +298,11 @@ class CustomSettings(object): if 'enemies' in self.file_source: return self.file_source['enemies'] return None + + def get_gtentry(self): + if 'gt_entry' in self.file_source: + return self.file_source['gt_entry'] + return None def get_attribute_by_player_composite(self, attribute, player): diff --git a/source/tools/MysteryUtils.py b/source/tools/MysteryUtils.py index 73d600e2..c7d811e3 100644 --- a/source/tools/MysteryUtils.py +++ b/source/tools/MysteryUtils.py @@ -16,6 +16,16 @@ def get_weights(path): return yaml.load(urllib.request.urlopen(path), Loader=yaml.FullLoader) def roll_settings(weights): + while True: + subweights = weights.get('subweights', {}) + if len(subweights) == 0: + break + chances = ({k: int(v['chance']) for (k, v) in subweights.items()}) + subweight_name = random.choices(list(chances.keys()), weights=list(chances.values()))[0] + subweights = weights.get('subweights', {}).get(subweight_name, {}).get('weights', {}) + subweights['subweights'] = subweights.get('subweights', {}) + weights = {**weights, **subweights} + def get_choice(option, root=None): root = weights if root is None else root if option not in root: @@ -65,16 +75,6 @@ def roll_settings(weights): return default return choice - while True: - subweights = weights.get('subweights', {}) - if len(subweights) == 0: - break - chances = ({k: int(v['chance']) for (k, v) in subweights.items()}) - subweight_name = random.choices(list(chances.keys()), weights=list(chances.values()))[0] - subweights = weights.get('subweights', {}).get(subweight_name, {}).get('weights', {}) - subweights['subweights'] = subweights.get('subweights', {}) - weights = {**weights, **subweights} - ret = argparse.Namespace() ret.algorithm = get_choice('algorithm')