Merge branch 'OverworldShuffleDev' into OverworldShuffle

This commit is contained in:
codemann8
2025-08-25 12:35:20 -05:00
8 changed files with 171 additions and 16 deletions

View File

@@ -1,5 +1,12 @@
# Changelog # 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 ## 0.6.0.5
- Emergency fix for map/key totals in non-DR - Emergency fix for map/key totals in non-DR

View File

@@ -8,7 +8,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType
from OverworldGlitchRules import create_owg_connections from OverworldGlitchRules import create_owg_connections
from Utils import bidict from Utils import bidict
version_number = '0.6.0.5' version_number = '0.6.0.6'
# branch indicator is intentionally different across branches # branch indicator is intentionally different across branches
version_branch = '' version_branch = ''

26
Rom.py
View File

@@ -43,7 +43,7 @@ from source.enemizer.Enemizer import write_enemy_shuffle_settings
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '94672b7a306b32c8a1d9e64f0e6a9be0' RANDOMIZERBASEHASH = 'b8c930c1922fb15018c76be902cc15d9'
class JsonRom(object): 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) 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 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) 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 0x3E, difficulty.boss_heart_container_limit, GREEN_TWENTY_RUPEES, 0xff, # boss heart -> green 20
0x17, difficulty.heart_piece_limit, 0x47, 0xff, # piece of 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 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_enemizer_tweaks(rom, world, player)
write_strings(rom, world, player, team) 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 # write initial sram
rom.write_initial_sram() rom.write_initial_sram()

View File

@@ -146,3 +146,102 @@ bonk_prize_lookup = {
'Arrows (10)': (0xe2, 0, None), 'Arrows (10)': (0xe2, 0, None),
'Fairy': (0xe3, 15, 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),
}

Binary file not shown.

View File

@@ -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. 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 This must be defined by player. You may have the prices of items in shops defined using the following
@@ -348,3 +348,27 @@ prices:
Dark Death Mountain Shop - Right: 300 Dark Death Mountain Shop - Right: 300
Dark Lake Hylia Shop - Left: 200 Dark Lake Hylia Shop - Left: 200
``` ```
### 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
```

View File

@@ -299,6 +299,11 @@ class CustomSettings(object):
return self.file_source['enemies'] return self.file_source['enemies']
return None 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): def get_attribute_by_player_composite(self, attribute, player):
attempt = self.get_attribute_by_player_new(attribute, player) attempt = self.get_attribute_by_player_new(attribute, player)

View File

@@ -16,6 +16,16 @@ def get_weights(path):
return yaml.load(urllib.request.urlopen(path), Loader=yaml.FullLoader) return yaml.load(urllib.request.urlopen(path), Loader=yaml.FullLoader)
def roll_settings(weights): 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): def get_choice(option, root=None):
root = weights if root is None else root root = weights if root is None else root
if option not in root: if option not in root:
@@ -65,16 +75,6 @@ def roll_settings(weights):
return default return default
return choice 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 = argparse.Namespace()
ret.algorithm = get_choice('algorithm') ret.algorithm = get_choice('algorithm')