10 Commits

9 changed files with 34 additions and 10 deletions

View File

@@ -85,6 +85,7 @@ class World(object):
self.bosses_ganon = {} self.bosses_ganon = {}
self.bosshunt_include_agas = {} self.bosshunt_include_agas = {}
self.ganon_item = {} self.ganon_item = {}
self.require_ganon_item = {}
self.ganon_item_orig = {} self.ganon_item_orig = {}
self.custom = custom self.custom = custom
self.customitemarray = customitemarray self.customitemarray = customitemarray
@@ -186,6 +187,7 @@ class World(object):
set_player_attr('bosses_ganon', 8) set_player_attr('bosses_ganon', 8)
set_player_attr('bosshunt_include_agas', False) set_player_attr('bosshunt_include_agas', False)
set_player_attr('ganon_item', 'silver') set_player_attr('ganon_item', 'silver')
set_player_attr('require_ganon_item', False)
set_player_attr('crystals_ganon_orig', {}) set_player_attr('crystals_ganon_orig', {})
set_player_attr('crystals_gt_orig', {}) set_player_attr('crystals_gt_orig', {})
set_player_attr('ganon_item_orig', 'silver') set_player_attr('ganon_item_orig', 'silver')
@@ -1407,7 +1409,7 @@ class CollectionState(object):
def can_hit_stunned_ganon(self, player): def can_hit_stunned_ganon(self, player):
ganon_item = self.world.ganon_item[player] ganon_item = self.world.ganon_item[player]
if ganon_item == "silver": if ganon_item == "silver":
return self.has("Silver Arroys", player) and self.can_shoot_arrows(player) return self.has("Silver Arrows", player) and self.can_shoot_arrows(player)
elif ganon_item == "boomerang": elif ganon_item == "boomerang":
return self.has("Blue Boomerang", player) or self.has("Red Boomerang", player) return self.has("Blue Boomerang", player) or self.has("Red Boomerang", player)
elif ganon_item == "hookshot": elif ganon_item == "hookshot":
@@ -3154,6 +3156,7 @@ class Spoiler(object):
'ganon_bosses': self.world.bosses_ganon, 'ganon_bosses': self.world.bosses_ganon,
'bosshunt_include_agas': self.world.bosshunt_include_agas, 'bosshunt_include_agas': self.world.bosshunt_include_agas,
'ganon_item': self.world.ganon_item, 'ganon_item': self.world.ganon_item,
'require_ganon_item': self.world.require_ganon_item,
'open_pyramid': self.world.open_pyramid, 'open_pyramid': self.world.open_pyramid,
'accessibility': self.world.accessibility, 'accessibility': self.world.accessibility,
'restricted_boss_items': self.world.restrict_boss_items, 'restricted_boss_items': self.world.restrict_boss_items,
@@ -3391,7 +3394,8 @@ class Spoiler(object):
if custom['murahgoal'] and 'requirements' in custom['murahgoal']: if custom['murahgoal'] and 'requirements' in custom['murahgoal']:
outfile.write('Murahdahla Requirement:'.ljust(line_width) + 'custom\n') outfile.write('Murahdahla Requirement:'.ljust(line_width) + 'custom\n')
outfile.write(' %s\n' % custom['murahgoal']['goaltext']) outfile.write(' %s\n' % custom['murahgoal']['goaltext'])
outfile.write('Item Required for Ganon:'.ljust(line_width) + '%s\n' % str(self.world.ganon_item_orig[player])) outfile.write('Item to Hurt Stunned Ganon:'.ljust(line_width) + '%s\n' % str(self.world.ganon_item_orig[player]))
outfile.write('Item Required for Ganon:'.ljust(line_width) + '%s\n' % yn(self.world.require_ganon_item[player]))
outfile.write('Swords:'.ljust(line_width) + '%s\n' % self.metadata['weapons'][player]) outfile.write('Swords:'.ljust(line_width) + '%s\n' % self.metadata['weapons'][player])
outfile.write('\n') outfile.write('\n')
outfile.write('Accessibility:'.ljust(line_width) + '%s\n' % self.metadata['accessibility'][player]) outfile.write('Accessibility:'.ljust(line_width) + '%s\n' % self.metadata['accessibility'][player])

4
CLI.py
View File

@@ -159,7 +159,8 @@ def parse_cli(argv, no_defaults=False):
'take_any', 'boots_hint', 'shuffle_followers', 'take_any', 'boots_hint', 'shuffle_followers',
'shuffle', 'door_shuffle', 'intensity', 'shuffle', 'door_shuffle', 'intensity',
'crystals_ganon', 'crystals_gt', 'bosses_ganon', 'crystals_ganon', 'crystals_gt', 'bosses_ganon',
'bosshunt_include_agas', 'ganon_item', 'openpyramid', 'bosshunt_include_agas', 'ganon_item',
'require_ganon_item', 'openpyramid',
'mapshuffle', 'compassshuffle', 'keyshuffle', 'mapshuffle', 'compassshuffle', 'keyshuffle',
'bigkeyshuffle', 'prizeshuffle', 'showloot', 'loothud', 'bigkeyshuffle', 'prizeshuffle', 'showloot', 'loothud',
'showmap', 'startinventory', 'usestartinventory', 'showmap', 'startinventory', 'usestartinventory',
@@ -220,6 +221,7 @@ def parse_settings():
"bosses_ganon": "8", "bosses_ganon": "8",
"bosshunt_include_agas": False, "bosshunt_include_agas": False,
"ganon_item": "silver", "ganon_item": "silver",
"require_ganon_item": False,
"swords": "random", "swords": "random",
"flute_mode": "normal", "flute_mode": "normal",
"bow_mode": "progressive", "bow_mode": "progressive",

View File

@@ -944,6 +944,7 @@ def customize_shops(world, player):
rep_price = final_price(loc.name, item.price, world, player) rep_price = final_price(loc.name, item.price, world, player)
shop.add_inventory(idx, upgrade.name, up_price, 6, shop.add_inventory(idx, upgrade.name, up_price, 6,
item.name, rep_price, player=item.player) item.name, rep_price, player=item.player)
upgrade.world = loc.item.world
loc.item = upgrade loc.item = upgrade
upgrade.location = loc upgrade.location = loc
if not found_arrow_upgrade and len(possible_replacements) > 0: if not found_arrow_upgrade and len(possible_replacements) > 0:
@@ -959,6 +960,7 @@ def customize_shops(world, player):
shop.add_inventory(idx, upgrade.name, up_price, 6, shop.add_inventory(idx, upgrade.name, up_price, 6,
item.name, rep_price, player=item.player) item.name, rep_price, player=item.player)
loc.item = upgrade loc.item = upgrade
upgrade.world = loc.item.world
upgrade.location = loc upgrade.location = loc
change_shop_items_to_rupees(world, player, shops_to_customize) change_shop_items_to_rupees(world, player, shops_to_customize)
balance_prices(world, player) balance_prices(world, player)
@@ -995,9 +997,11 @@ def change_shop_items_to_rupees(world, player, shops):
for location in locations: for location in locations:
if location.item.name in shop_transfer.keys() and (location.parent_region.name not in shops or location.name == 'Potion Shop'): if location.item.name in shop_transfer.keys() and (location.parent_region.name not in shops or location.name == 'Potion Shop'):
new_item = ItemFactory(shop_transfer[location.item.name], location.item.player) new_item = ItemFactory(shop_transfer[location.item.name], location.item.player)
new_item.world = location.item.world
location.item = new_item location.item = new_item
if location.parent_region.name == 'Capacity Upgrade' and location.item.name in cap_blacklist: if location.parent_region.name == 'Capacity Upgrade' and location.item.name in cap_blacklist:
new_item = ItemFactory('Rupees (300)', location.item.player) new_item = ItemFactory('Rupees (300)', location.item.player)
new_item.world = location.item.world
location.item = new_item location.item = new_item
shop = world.get_region('Capacity Upgrade', player).shop shop = world.get_region('Capacity Upgrade', player).shop
slot = shop_to_location_table['Capacity Upgrade'].index(location.name) slot = shop_to_location_table['Capacity Upgrade'].index(location.name)

View File

@@ -546,6 +546,7 @@ def init_world(args, fish):
world.crystals_ganon_orig = args.crystals_ganon.copy() world.crystals_ganon_orig = args.crystals_ganon.copy()
world.crystals_gt_orig = args.crystals_gt.copy() world.crystals_gt_orig = args.crystals_gt.copy()
world.ganon_item_orig = args.ganon_item.copy() world.ganon_item_orig = args.ganon_item.copy()
world.require_ganon_item = args.require_ganon_item.copy()
world.bosses_ganon = {player: int(args.bosses_ganon[player]) for player in range(1, world.players + 1)} world.bosses_ganon = {player: int(args.bosses_ganon[player]) for player in range(1, world.players + 1)}
world.bosshunt_include_agas = args.bosshunt_include_agas.copy() world.bosshunt_include_agas = args.bosshunt_include_agas.copy()
world.owTerrain = args.ow_terrain.copy() world.owTerrain = args.ow_terrain.copy()
@@ -871,6 +872,7 @@ def copy_world(world):
ret.bosses_ganon = world.bosses_ganon.copy() ret.bosses_ganon = world.bosses_ganon.copy()
ret.bosshunt_include_agas = world.bosshunt_include_agas.copy() ret.bosshunt_include_agas = world.bosshunt_include_agas.copy()
ret.ganon_item = world.ganon_item.copy() ret.ganon_item = world.ganon_item.copy()
ret.require_ganon_item = world.require_ganon_item.copy()
ret.crystals_ganon_orig = world.crystals_ganon_orig.copy() ret.crystals_ganon_orig = world.crystals_ganon_orig.copy()
ret.crystals_gt_orig = world.crystals_gt_orig.copy() ret.crystals_gt_orig = world.crystals_gt_orig.copy()
ret.ganon_item_orig = world.ganon_item_orig.copy() ret.ganon_item_orig = world.ganon_item_orig.copy()
@@ -1105,6 +1107,7 @@ def copy_world_premature(world, player, create_flute_exits=True):
ret.bosses_ganon = world.bosses_ganon.copy() ret.bosses_ganon = world.bosses_ganon.copy()
ret.bosshunt_include_agas = world.bosshunt_include_agas.copy() ret.bosshunt_include_agas = world.bosshunt_include_agas.copy()
ret.ganon_item = world.ganon_item.copy() ret.ganon_item = world.ganon_item.copy()
ret.require_ganon_item = world.require_ganon_item.copy()
ret.crystals_ganon_orig = world.crystals_ganon_orig.copy() ret.crystals_ganon_orig = world.crystals_ganon_orig.copy()
ret.crystals_gt_orig = world.crystals_gt_orig.copy() ret.crystals_gt_orig = world.crystals_gt_orig.copy()
ret.ganon_item_orig = world.ganon_item_orig.copy() ret.ganon_item_orig = world.ganon_item_orig.copy()

9
Rom.py
View File

@@ -85,7 +85,7 @@ from Utils import int16_as_bytes, int32_as_bytes, local_path, snes_to_pc
from Versions import DRVersion, GKVersion, ORVersion from Versions import DRVersion, GKVersion, ORVersion
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '94ff6d50db131aabe6b086e783709004' RANDOMIZERBASEHASH = 'd80446af9eeb1726d2b6c1303bec1226'
class JsonRom(object): class JsonRom(object):
@@ -1452,7 +1452,12 @@ def patch_rom(world, rom, player, team, is_mystery=False, rom_header=None):
"byrna": 0x12, "byrna": 0x12,
"none": 0x7F, "none": 0x7F,
} }
rom.write_byte(0x18002E, ganon_item_byte[world.ganon_item[player]]) ganon_item_value = ganon_item_byte[world.ganon_item[player]]
if world.require_ganon_item[player] and world.ganon_item[player] != "none":
if world.swords[player] != "swordless" or world.ganon_item[player] not in ["bombos", "ether", "quake"]:
ganon_item_value |= 0x80
rom.write_byte(0x18002E, ganon_item_value)
# block HC upstairs doors in rain state in standard mode # block HC upstairs doors in rain state in standard mode
prevent_rain = world.mode[player] == 'standard' and world.shuffle[player] != 'vanilla' and world.logic[player] != 'nologic' prevent_rain = world.mode[player] == 'standard' and world.shuffle[player] != 'vanilla' and world.logic[player] != 'nologic'

View File

@@ -1026,10 +1026,11 @@ def global_rules(world, player):
world.get_location('Ganon', player), world.get_location('Ganon', player),
lambda state: state.has_beam_sword(player) lambda state: state.has_beam_sword(player)
and state.has_fire_source(player) and state.has_fire_source(player)
and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) and (state.can_hit_stunned_ganon(player) or (
or state.can_hit_stunned_ganon(player) not world.require_ganon_item[player] and (
or state.has('Lamp', player) state.has('Tempered Sword', player) or state.has('Golden Sword', player)
or state.can_extend_magic(player, 12))) # need to light torch a sufficient amount of times or state.has('Lamp', player)
or state.can_extend_magic(player, 12))))) # need to light torch a sufficient amount of times
set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has_beam_sword(player)) # need to damage ganon to get tiles to drop set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has_beam_sword(player)) # need to damage ganon to get tiles to drop

View File

@@ -2054,5 +2054,6 @@ class TextTable(object):
text['ganon_phase_3_silvers'] = CompressedTextMapper.convert("Oh no! Silver! My one true weakness!") text['ganon_phase_3_silvers'] = CompressedTextMapper.convert("Oh no! Silver! My one true weakness!")
text['murahdahla'] = CompressedTextMapper.convert("Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n{PAUSE3}\n… … …\nWait! You can see me? I knew I should have\nhidden in a hollow tree.") text['murahdahla'] = CompressedTextMapper.convert("Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n{PAUSE3}\n… … …\nWait! You can see me? I knew I should have\nhidden in a hollow tree.")
text['mastersword_pedestal_goal'] = CompressedTextMapper.convert("To claim thy reward, you must present all 3 Pendants of Virtue.") text['mastersword_pedestal_goal'] = CompressedTextMapper.convert("To claim thy reward, you must present all 3 Pendants of Virtue.")
text['end_pad_data'] = bytearray([0xfb]) text['orange_potion_refill'] = CompressedTextMapper.convert("This rare orange potion will give you infinite magic, but only until you die or quit the game.")
text['end_pad_data'] = bytearray([0xFB])
text['terminator'] = bytearray([0xFF, 0xFF]) text['terminator'] = bytearray([0xFF, 0xFF])

Binary file not shown.

View File

@@ -378,6 +378,10 @@
"none" "none"
] ]
}, },
"require_ganon_item": {
"action": "store_true",
"type": "bool"
},
"beemizer": { "beemizer": {
"choices": [ "choices": [
"4", "3", "2", "1", "0" "4", "3", "2", "1", "0"