Ganonhunt

This commit is contained in:
cassidoxa
2023-06-12 13:52:17 -04:00
parent 0c871a2239
commit c4e6fbb8cd
4 changed files with 41 additions and 14 deletions

View File

@@ -55,7 +55,7 @@ def start():
Palace, to allow for an alternative to firerod. Palace, to allow for an alternative to firerod.
Vanilla: Swords are in vanilla locations. Vanilla: Swords are in vanilla locations.
''') ''')
parser.add_argument('--goal', default='ganon', const='ganon', nargs='?', choices=['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals', 'all_items', 'completionist'], parser.add_argument('--goal', default='ganon', const='ganon', nargs='?', choices=['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'ganonhunt', 'crystals', 'all_items', 'completionist'],
help='''\ help='''\
Select completion goal. (default: %(default)s) Select completion goal. (default: %(default)s)
Ganon: Collect all crystals, beat Agahnim 2 then Ganon: Collect all crystals, beat Agahnim 2 then
@@ -66,6 +66,8 @@ def start():
Agahnim fights and then defeat Ganon. Agahnim fights and then defeat Ganon.
Triforce Hunt: Places 30 Triforce Pieces in the world, collect Triforce Hunt: Places 30 Triforce Pieces in the world, collect
20 of them to beat the game. 20 of them to beat the game.
Ganonhunt: Places 30 Triforce Pieces in the world, collect
20 of them to beat Ganon.
All Items: Requires collecting 216 items to defeat Ganon. All Items: Requires collecting 216 items to defeat Ganon.
Completionist: Same as above, plus All Dungeons Completionist: Same as above, plus All Dungeons
''') ''')

View File

@@ -35,8 +35,8 @@ Difficulty = namedtuple('Difficulty',
['baseitems', 'bottles', 'bottle_count', 'same_bottle', 'progressiveshield', ['baseitems', 'bottles', 'bottle_count', 'same_bottle', 'progressiveshield',
'basicshield', 'progressivearmor', 'basicarmor', 'swordless', 'basicshield', 'progressivearmor', 'basicarmor', 'swordless',
'progressivesword', 'basicsword', 'basicbow', 'timedohko', 'timedother', 'progressivesword', 'basicsword', 'basicbow', 'timedohko', 'timedother',
'triforcehunt', 'triforce_pieces_required', 'retro', 'triforcehunt', 'ganonhunt', 'triforce_pieces_required', 'ganonhunt_pieces_required',
'extras', 'progressive_sword_limit', 'progressive_shield_limit', 'retro', 'extras', 'progressive_sword_limit', 'progressive_shield_limit',
'progressive_armor_limit', 'progressive_bottle_limit', 'progressive_armor_limit', 'progressive_bottle_limit',
'progressive_bow_limit', 'heart_piece_limit', 'boss_heart_container_limit']) 'progressive_bow_limit', 'heart_piece_limit', 'boss_heart_container_limit'])
@@ -59,7 +59,9 @@ difficulties = {
timedohko = ['Green Clock'] * 25, timedohko = ['Green Clock'] * 25,
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10, timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
triforcehunt = ['Triforce Piece'] * 30, triforcehunt = ['Triforce Piece'] * 30,
ganonhunt = ['Triforce Piece'] * 50,
triforce_pieces_required = 20, triforce_pieces_required = 20,
ganonhunt_pieces_required = 40,
retro = ['Small Key (Universal)'] * 17 + ['Rupees (20)'] * 10, retro = ['Small Key (Universal)'] * 17 + ['Rupees (20)'] * 10,
extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra], extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra],
progressive_sword_limit = 4, progressive_sword_limit = 4,
@@ -86,7 +88,9 @@ difficulties = {
timedohko = ['Green Clock'] * 25, timedohko = ['Green Clock'] * 25,
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10, timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
triforcehunt = ['Triforce Piece'] * 30, triforcehunt = ['Triforce Piece'] * 30,
ganonhunt = ['Triforce Piece'] * 50,
triforce_pieces_required = 20, triforce_pieces_required = 20,
ganonhunt_pieces_required = 40,
retro = ['Small Key (Universal)'] * 12 + ['Rupees (5)'] * 15, retro = ['Small Key (Universal)'] * 12 + ['Rupees (5)'] * 15,
extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra], extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra],
progressive_sword_limit = 3, progressive_sword_limit = 3,
@@ -113,7 +117,9 @@ difficulties = {
timedohko = ['Green Clock'] * 20 + ['Red Clock'] * 5, timedohko = ['Green Clock'] * 20 + ['Red Clock'] * 5,
timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10, timedother = ['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
triforcehunt = ['Triforce Piece'] * 30, triforcehunt = ['Triforce Piece'] * 30,
ganonhunt = ['Triforce Piece'] * 50,
triforce_pieces_required = 20, triforce_pieces_required = 20,
ganonhunt_pieces_required = 40,
retro = ['Small Key (Universal)'] * 12 + ['Rupees (5)'] * 15, retro = ['Small Key (Universal)'] * 12 + ['Rupees (5)'] * 15,
extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra], extras = [normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra],
progressive_sword_limit = 2, progressive_sword_limit = 2,
@@ -127,7 +133,7 @@ difficulties = {
} }
def generate_itempool(world, player): def generate_itempool(world, player):
if (world.difficulty not in ['normal', 'hard', 'expert'] or world.goal not in ['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'crystals', 'all_items', 'completionist'] if (world.difficulty not in ['normal', 'hard', 'expert'] or world.goal not in ['ganon', 'pedestal', 'dungeons', 'triforcehunt', 'ganonhunt', 'crystals', 'all_items', 'completionist']
or world.mode not in ['open', 'standard', 'inverted'] or world.timer not in ['none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown'] or world.progressive not in ['on', 'off', 'random']): or world.mode not in ['open', 'standard', 'inverted'] or world.timer not in ['none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown'] or world.progressive not in ['on', 'off', 'random']):
raise NotImplementedError('Not supported yet') raise NotImplementedError('Not supported yet')
@@ -457,11 +463,16 @@ def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, r
pool.extend(diff.timedohko) pool.extend(diff.timedohko)
extraitems -= len(diff.timedohko) extraitems -= len(diff.timedohko)
clock_mode = 'countdown-ohko' clock_mode = 'countdown-ohko'
if goal == 'triforcehunt': if goal in ['triforcehunt']:
pool.extend(diff.triforcehunt) pool.extend(diff.triforcehunt)
extraitems -= len(diff.triforcehunt) extraitems -= len(diff.triforcehunt)
treasure_hunt_count = diff.triforce_pieces_required treasure_hunt_count = diff.triforce_pieces_required
treasure_hunt_icon = 'Triforce Piece' treasure_hunt_icon = 'Triforce Piece'
if goal in ['ganonhunt']:
pool.extend(diff.ganonhunt)
extraitems -= len(diff.ganonhunt)
treasure_hunt_count = diff.ganonhunt_pieces_required
treasure_hunt_icon = 'Triforce Piece'
for extra in diff.extras: for extra in diff.extras:
if extraitems > 0: if extraitems > 0:
@@ -582,7 +593,7 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s
treasure_hunt_count = max(min(customitemarray[65], 99), 1) #To display, count must be between 1 and 99. treasure_hunt_count = max(min(customitemarray[65], 99), 1) #To display, count must be between 1 and 99.
treasure_hunt_icon = 'Triforce Piece' treasure_hunt_icon = 'Triforce Piece'
# Ensure game is always possible to complete here, force sufficient pieces if the player is unwilling. # Ensure game is always possible to complete here, force sufficient pieces if the player is unwilling.
if (customitemarray[64] < treasure_hunt_count) and (goal == 'triforcehunt') and (customitemarray[66] == 0): if (customitemarray[64] < treasure_hunt_count) and (goal in ['triforcehunt', 'ganonhunt']) and (customitemarray[66] == 0):
extrapieces = treasure_hunt_count - customitemarray[64] extrapieces = treasure_hunt_count - customitemarray[64]
pool.extend(['Triforce Piece'] * extrapieces) pool.extend(['Triforce Piece'] * extrapieces)
itemtotal = itemtotal + extrapieces itemtotal = itemtotal + extrapieces

18
Rom.py
View File

@@ -905,6 +905,8 @@ def patch_rom(world, player, rom):
rom.write_byte(0x18003E, 0x0A) # make ganon invincible until all items rom.write_byte(0x18003E, 0x0A) # make ganon invincible until all items
elif world.goal in ['completionist']: elif world.goal in ['completionist']:
rom.write_byte(0x18003E, 0x0B) # make ganon invincible until all items and dungeons rom.write_byte(0x18003E, 0x0B) # make ganon invincible until all items and dungeons
elif world.goal in ['ganonhunt']:
rom.write_byte(0x18003E, 0x05) # make ganon invincible until goal triforce pieces
else: else:
rom.write_byte(0x18003E, 0x03) # make ganon invincible until all crystals and aga 2 are collected rom.write_byte(0x18003E, 0x03) # make ganon invincible until all crystals and aga 2 are collected
@@ -1040,7 +1042,7 @@ def patch_rom(world, player, rom):
# write total item count and item counter hud mode # write total item count and item counter hud mode
item_total = len(world.get_filled_locations()) - 18 # minus non-item locations item_total = len(world.get_filled_locations()) - 18 # minus non-item locations
rom.write_int16(0x180196, item_total+1) rom.write_int16(0x180196, item_total+1)
if world.item_counter_hud[player] and world.goal != 'triforcehunt': if world.item_counter_hud[player] and world.goal not in ['triforcehunt', 'ganonhunt']:
rom.write_byte(0x180039, 0x01) rom.write_byte(0x180039, 0x01)
else: else:
rom.write_byte(0x180039, 0x00) rom.write_byte(0x180039, 0x00)
@@ -1337,10 +1339,11 @@ def write_strings(rom, world, player):
if world.goal == 'ganon': if world.goal == 'ganon':
ganon_crystals_singular = 'To beat Ganon you must collect %d crystal and defeat his minion at the top of his tower.' ganon_crystals_singular = 'To beat Ganon you must collect %d crystal and defeat his minion at the top of his tower.'
ganon_crystals_plural = 'To beat Ganon you must collect %d crystals and defeat his minion at the top of his tower.' ganon_crystals_plural = 'To beat Ganon you must collect %d crystals and defeat his minion at the top of his tower.'
tt['sign_ganon'] = (ganon_crystals_singular if world.crystals_needed_for_ganon == 1 else ganon_crystals_plural) % world.crystals_needed_for_ganon
tt['sign_ganon'] = (ganon_crystals_singular if world.crystals_needed_for_ganon == 1 else ganon_crystals_plural) % world.crystals_needed_for_ganon if world.goal == 'ganonhunt':
ganon_triforce_singular = 'To beat Ganon you must collect %d triforce pieces and defeat his minion at the top of his tower.'
ganon_triforce_plural = 'To beat Ganon you must collect %d triforce pieces and defeat his minion at the top of his tower.'
tt['sign_ganon'] = (ganon_triforce_singular if world.treasure_hunt_count == 1 else ganon_triforce_plural) % world.treasure_hunt_count
if world.goal in ['dungeons']: if world.goal in ['dungeons']:
tt['sign_ganon'] = 'You need to complete all the dungeons.' tt['sign_ganon'] = 'You need to complete all the dungeons.'
@@ -1358,6 +1361,11 @@ def write_strings(rom, world, player):
tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.' tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.'
tt['sign_ganon'] = 'Go find the Triforce pieces... Ganon is invincible!' tt['sign_ganon'] = 'Go find the Triforce pieces... Ganon is invincible!'
tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n\n\n\n… … …\n\nWait! you can see me? I knew I should have\nhidden in a hollow tree. If you bring\n%d triforce pieces, I can reassemble it." % world.treasure_hunt_count tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\ninvisibility.\n\n\n\n… … …\n\nWait! you can see me? I knew I should have\nhidden in a hollow tree. If you bring\n%d triforce pieces, I can reassemble it." % world.treasure_hunt_count
elif world.goal in ['ganonhunt']:
tt['ganon_fall_in'] = Ganon1_texts[random.randint(0, len(Ganon1_texts) - 1)]
tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me! Get the Triforce Pieces.'
tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.'
tt['sign_ganon'] = 'You need %d triforce pieces to beat Ganon.'
elif world.goal in ['pedestal']: elif world.goal in ['pedestal']:
tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me! Your goal is at the pedestal.' tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me! Your goal is at the pedestal.'
tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.' tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.'

View File

@@ -466,7 +466,10 @@ def global_rules(world, player):
forbid_item(world.get_location(location, player), 'Big Key (Ganons Tower)', player) forbid_item(world.get_location(location, player), 'Big Key (Ganons Tower)', player)
set_rule(world.get_location('Ganon', player), lambda state: state.has_beam_sword(player) and state.has_fire_source(player) and state.has_crystals(world.crystals_needed_for_ganon, player) set_rule(world.get_location('Ganon', player), lambda state: state.has_beam_sword(player) and state.has_fire_source(player) and state.has_crystals(world.crystals_needed_for_ganon, player)
and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (state.has('Silver Arrows', player) and state.can_shoot_arrows(player)) or state.has('Lamp', player) or state.can_extend_magic(player, 12))) # need to light torch a sufficient amount of times and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (state.has('Silver Arrows', player) and state.can_shoot_arrows(player)) or state.has('Lamp', player) or state.can_extend_magic(player, 12))
and (False if world.goal == 'completionist' and (world.accessibility != 'locations') else True)
and (False if (world.goal == 'ganonhunt' and not state.has('Triforce Piece', player, world.treasure_hunt_count)) else True)
)
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
set_rule(world.get_entrance('Ganons Tower', player), lambda state: False) # This is a safety for the TR function below to not require GT entrance in its key logic. set_rule(world.get_entrance('Ganons Tower', player), lambda state: False) # This is a safety for the TR function below to not require GT entrance in its key logic.
@@ -876,7 +879,10 @@ def inverted_rules(world, player):
forbid_item(world.get_location(location, player), 'Big Key (Ganons Tower)', player) forbid_item(world.get_location(location, player), 'Big Key (Ganons Tower)', player)
set_rule(world.get_location('Ganon', player), lambda state: state.has_beam_sword(player) and state.has_fire_source(player) and state.has_crystals(world.crystals_needed_for_ganon, player) set_rule(world.get_location('Ganon', player), lambda state: state.has_beam_sword(player) and state.has_fire_source(player) and state.has_crystals(world.crystals_needed_for_ganon, player)
and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (state.has('Silver Arrows', player) and state.can_shoot_arrows(player)) or state.has('Lamp', player) or state.can_extend_magic(player, 12))) # need to light torch a sufficient amount of times and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (state.has('Silver Arrows', player) and state.can_shoot_arrows(player)) or state.has('Lamp', player) or state.can_extend_magic(player, 12))
and (False if world.goal == 'completionist' and (world.accessibility != 'locations') else True)
and (False if (world.goal == 'ganonhunt' and not state.has('Triforce Piece', player, world.treasure_hunt_count)) else True)
)
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
set_rule(world.get_entrance('Inverted Ganons Tower', player), lambda state: False) # This is a safety for the TR function below to not require GT entrance in its key logic. set_rule(world.get_entrance('Inverted Ganons Tower', player), lambda state: False) # This is a safety for the TR function below to not require GT entrance in its key logic.
@@ -1055,7 +1061,7 @@ def set_trock_key_rules(world, player):
# No matter what, the Big Key cannot be in the Big Chest or held by Trinexx. # No matter what, the Big Key cannot be in the Big Chest or held by Trinexx.
non_big_key_locations = ['Turtle Rock - Big Chest', 'Turtle Rock - Boss'] non_big_key_locations = ['Turtle Rock - Big Chest', 'Turtle Rock - Boss']
def tr_big_key_chest_keys_needed(world, state): def tr_big_key_chest_keys_needed(state):
# This function handles the key requirements for the TR Big Chest in the situations it having the Big Key should logically require 2 keys, small key # This function handles the key requirements for the TR Big Chest in the situations it having the Big Key should logically require 2 keys, small key
# should logically require no keys, and anything else should logically require 4 keys. # should logically require no keys, and anything else should logically require 4 keys.
item = item_name(state, 'Turtle Rock - Big Key Chest', player) item = item_name(state, 'Turtle Rock - Big Key Chest', player)