All futuro code - apart from logic
This commit is contained in:
@@ -92,6 +92,9 @@ class World(object):
|
|||||||
self.retro[player] = True
|
self.retro[player] = True
|
||||||
def set_player_attr(attr, val):
|
def set_player_attr(attr, val):
|
||||||
self.__dict__.setdefault(attr, {})[player] = val
|
self.__dict__.setdefault(attr, {})[player] = val
|
||||||
|
# Futuro doesn't support standard start
|
||||||
|
if self.futuro[player] and self.mode[player] == "standard":
|
||||||
|
self.mode[player] == "open"
|
||||||
set_player_attr('_region_cache', {})
|
set_player_attr('_region_cache', {})
|
||||||
set_player_attr('player_names', [])
|
set_player_attr('player_names', [])
|
||||||
set_player_attr('remote_items', False)
|
set_player_attr('remote_items', False)
|
||||||
@@ -451,6 +454,9 @@ class World(object):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
# Items to test for ability to use magic in has()
|
||||||
|
magic_items = ['Magic Powder', 'Fire Rod', 'Ice Rod', 'Bombos', 'Ether', 'Quake', 'Cane of Somaria', 'Cane of Byrna', 'Cape']
|
||||||
|
|
||||||
class CollectionState(object):
|
class CollectionState(object):
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
@@ -597,6 +603,9 @@ class CollectionState(object):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def has(self, item, player, count=1):
|
def has(self, item, player, count=1):
|
||||||
|
if self.world.futuro[player]:
|
||||||
|
if item in magic_items and self.prog_items['Magic Upgrade (1/2)', player] == 0 and self.prog_items['Magic Upgrade (1/4)', player] == 0:
|
||||||
|
return False
|
||||||
if count == 1:
|
if count == 1:
|
||||||
return (item, player) in self.prog_items
|
return (item, player) in self.prog_items
|
||||||
return self.prog_items[item, player] >= count
|
return self.prog_items[item, player] >= count
|
||||||
@@ -650,11 +659,17 @@ class CollectionState(object):
|
|||||||
return self.has('Titans Mitts', player)
|
return self.has('Titans Mitts', player)
|
||||||
|
|
||||||
def can_extend_magic(self, player, smallmagic=16, fullrefill=False): #This reflects the total magic Link has, not the total extra he has.
|
def can_extend_magic(self, player, smallmagic=16, fullrefill=False): #This reflects the total magic Link has, not the total extra he has.
|
||||||
basemagic = 8
|
|
||||||
if self.has('Magic Upgrade (1/4)', player):
|
if self.has('Magic Upgrade (1/4)', player):
|
||||||
basemagic = 32
|
basemagic = 32
|
||||||
elif self.has('Magic Upgrade (1/2)', player):
|
elif self.has('Magic Upgrade (1/2)', player):
|
||||||
basemagic = 16
|
basemagic = 16
|
||||||
|
else:
|
||||||
|
basemagic = 8
|
||||||
|
if self.world.futuro[player]:
|
||||||
|
if basemagic == 8:
|
||||||
|
basemagic = 0
|
||||||
|
else:
|
||||||
|
basemagic = int(basemagic/2)
|
||||||
if self.can_buy_unlimited('Green Potion', player) or self.can_buy_unlimited('Blue Potion', player):
|
if self.can_buy_unlimited('Green Potion', player) or self.can_buy_unlimited('Blue Potion', player):
|
||||||
if self.world.difficulty_adjustments[player] == 'hard' and not fullrefill:
|
if self.world.difficulty_adjustments[player] == 'hard' and not fullrefill:
|
||||||
basemagic = basemagic + int(basemagic * 0.5 * self.bottle_count(player))
|
basemagic = basemagic + int(basemagic * 0.5 * self.bottle_count(player))
|
||||||
@@ -670,8 +685,24 @@ class CollectionState(object):
|
|||||||
or (self.has('Cane of Byrna', player) and (enemies < 6 or self.can_extend_magic(player)))
|
or (self.has('Cane of Byrna', player) and (enemies < 6 or self.can_extend_magic(player)))
|
||||||
or self.can_shoot_arrows(player)
|
or self.can_shoot_arrows(player)
|
||||||
or self.has('Fire Rod', player)
|
or self.has('Fire Rod', player)
|
||||||
|
or (self.can_use_bombs(player) and enemies < 6)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def can_use_bombs(self, player):
|
||||||
|
return (self.has('Bomb Upgrade (+10)', player) or not self.world.futuro[player])
|
||||||
|
|
||||||
|
def can_hit_switch(self, player):
|
||||||
|
return (self.can_use_bombs(player)
|
||||||
|
or self.can_shoot_arrows(player)
|
||||||
|
or self.has_blunt_weapon(player)
|
||||||
|
or self.has('Blue Boomerang', player)
|
||||||
|
or self.has('Red Boomerang', player)
|
||||||
|
or self.has('Hookshot', player)
|
||||||
|
or self.has('Fire Rod', player)
|
||||||
|
or self.has('Ice Rod', player)
|
||||||
|
or self.has('Cane of Somaria', player)
|
||||||
|
or self.has('Cane of Byrna', player))
|
||||||
|
|
||||||
def can_shoot_arrows(self, player):
|
def can_shoot_arrows(self, player):
|
||||||
if self.world.retro[player]:
|
if self.world.retro[player]:
|
||||||
#todo: Non-progressive silvers grant wooden arrows, but progressive bows do not. Always require shop arrows to be safe
|
#todo: Non-progressive silvers grant wooden arrows, but progressive bows do not. Always require shop arrows to be safe
|
||||||
|
|||||||
19
ItemList.py
19
ItemList.py
@@ -604,6 +604,25 @@ def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode, swords, r
|
|||||||
pool.extend(['Small Key (Universal)'])
|
pool.extend(['Small Key (Universal)'])
|
||||||
else:
|
else:
|
||||||
pool.extend(['Small Key (Universal)'])
|
pool.extend(['Small Key (Universal)'])
|
||||||
|
|
||||||
|
if futuro:
|
||||||
|
magic_count = 0
|
||||||
|
bomb_count = 0
|
||||||
|
for item in pool:
|
||||||
|
if item == 'Magic Upgrade (1/2)':
|
||||||
|
magic_count += 1
|
||||||
|
if item == 'Bomb Upgrade (+10)':
|
||||||
|
bomb_count += 1
|
||||||
|
if magic_count == 0:
|
||||||
|
pool.append('Magic Upgrade (1/2)')
|
||||||
|
if 'Magic Upgrade (1/4)' not in pool and magic_count < 2:
|
||||||
|
pool.append('Magic Upgrade (1/2)')
|
||||||
|
if bomb_count == 0:
|
||||||
|
pool.append('Bomb Upgrade (+10)')
|
||||||
|
pool.append('Bomb Upgrade (+10)')
|
||||||
|
elif bomb_count == 1:
|
||||||
|
pool.append('Bomb Upgrade (+10)')
|
||||||
|
|
||||||
return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms)
|
return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon, lamps_needed_for_dark_rooms)
|
||||||
|
|
||||||
def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, futuro, customitemarray):
|
def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, swords, retro, futuro, customitemarray):
|
||||||
|
|||||||
@@ -174,6 +174,8 @@ def roll_settings(weights):
|
|||||||
ret.mode = 'open'
|
ret.mode = 'open'
|
||||||
ret.retro = True
|
ret.retro = True
|
||||||
|
|
||||||
|
ret.futuro = get_choice('futuro', weights)
|
||||||
|
|
||||||
ret.hints = get_choice('hints') == 'on'
|
ret.hints = get_choice('hints') == 'on'
|
||||||
|
|
||||||
ret.swords = {'randomized': 'random',
|
ret.swords = {'randomized': 'random',
|
||||||
|
|||||||
58
Rom.py
58
Rom.py
@@ -830,6 +830,21 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
|
|
||||||
rom.write_byte(0x18004F, 0x01) # Byrna Invulnerability: on
|
rom.write_byte(0x18004F, 0x01) # Byrna Invulnerability: on
|
||||||
|
|
||||||
|
# Default magic consumption costs
|
||||||
|
magic_cost = {
|
||||||
|
'Fire and Ice': [0x3B070, [0x10, 0x08, 0x04]],
|
||||||
|
'Medallions': [0x3B073, [0x20, 0x10, 0x08]],
|
||||||
|
'Magic Powder': [0x3B076, [0x08, 0x04, 0x02]],
|
||||||
|
'Unknown 1': [0x3B079, [0x08, 0x04, 0x02]],
|
||||||
|
'Cane of Somaria': [0x3B07C, [0x08, 0x04, 0x02]],
|
||||||
|
'Unknown 2': [0x3B07F, [0x10, 0x08, 0x04]],
|
||||||
|
'Lamp': [0x3B082, [0x04, 0x02, 0x02]],
|
||||||
|
'Unknown 3': [0x3B085, [0x08, 0x04, 0x02]],
|
||||||
|
'Cane of Byrna Activation': [0x3B088, [0x10, 0x08, 0x04]],
|
||||||
|
'Magic Cape Residual': [0x3ADA7, [0x04, 0x08, 0x10]],
|
||||||
|
'Cane of Byrna Residual': [0x45C42, [0x04, 0x02, 0x01]]
|
||||||
|
}
|
||||||
|
|
||||||
# handle difficulty_adjustments
|
# handle difficulty_adjustments
|
||||||
if world.difficulty_adjustments[player] == 'hard':
|
if world.difficulty_adjustments[player] == 'hard':
|
||||||
rom.write_byte(0x180181, 0x01) # Make silver arrows work only on ganon
|
rom.write_byte(0x180181, 0x01) # Make silver arrows work only on ganon
|
||||||
@@ -841,7 +856,7 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
# potion magic restore amount
|
# potion magic restore amount
|
||||||
rom.write_byte(0x180085, 0x40) # Half Magic
|
rom.write_byte(0x180085, 0x40) # Half Magic
|
||||||
#Cape magic cost
|
#Cape magic cost
|
||||||
rom.write_bytes(0x3ADA7, [0x02, 0x04, 0x08])
|
magic_cost['Magic Cape Residual'][1] = [0x02, 0x04, 0x08]
|
||||||
# Byrna Invulnerability: off
|
# Byrna Invulnerability: off
|
||||||
rom.write_byte(0x18004F, 0x00)
|
rom.write_byte(0x18004F, 0x00)
|
||||||
#Disable catching fairies
|
#Disable catching fairies
|
||||||
@@ -861,7 +876,7 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
# potion magic restore amount
|
# potion magic restore amount
|
||||||
rom.write_byte(0x180085, 0x20) # Quarter Magic
|
rom.write_byte(0x180085, 0x20) # Quarter Magic
|
||||||
#Cape magic cost
|
#Cape magic cost
|
||||||
rom.write_bytes(0x3ADA7, [0x02, 0x04, 0x08])
|
magic_cost['Magic Cape Residual'][1] = [0x02, 0x04, 0x08]
|
||||||
# Byrna Invulnerability: off
|
# Byrna Invulnerability: off
|
||||||
rom.write_byte(0x18004F, 0x00)
|
rom.write_byte(0x18004F, 0x00)
|
||||||
#Disable catching fairies
|
#Disable catching fairies
|
||||||
@@ -881,7 +896,7 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
# potion magic restore amount
|
# potion magic restore amount
|
||||||
rom.write_byte(0x180085, 0x80) # full
|
rom.write_byte(0x180085, 0x80) # full
|
||||||
#Cape magic cost
|
#Cape magic cost
|
||||||
rom.write_bytes(0x3ADA7, [0x04, 0x08, 0x10])
|
magic_cost['Magic Cape Residual'][1] = [0x04, 0x08, 0x10]
|
||||||
# Byrna Invulnerability: on
|
# Byrna Invulnerability: on
|
||||||
rom.write_byte(0x18004F, 0x01)
|
rom.write_byte(0x18004F, 0x01)
|
||||||
#Enable catching fairies
|
#Enable catching fairies
|
||||||
@@ -896,11 +911,21 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
else:
|
else:
|
||||||
overflow_replacement = GREEN_TWENTY_RUPEES
|
overflow_replacement = GREEN_TWENTY_RUPEES
|
||||||
|
|
||||||
#Byrna residual magic cost
|
|
||||||
rom.write_bytes(0x45C42, [0x04, 0x02, 0x01])
|
|
||||||
|
|
||||||
difficulty = world.difficulty_requirements[player]
|
difficulty = world.difficulty_requirements[player]
|
||||||
|
|
||||||
|
#Shift magic consumption costs if futuro
|
||||||
|
if world.futuro[player]:
|
||||||
|
for item in magic_cost:
|
||||||
|
magic_cost[item][1][2] = magic_cost[item][1][1]
|
||||||
|
magic_cost[item][1][1] = magic_cost[item][1][0]
|
||||||
|
magic_cost[item][1][0] = 0x81
|
||||||
|
# Cape consumpion is a cost/X tick thing
|
||||||
|
magic_cost['Magic Cape Residual'][1][0] = 0x01
|
||||||
|
|
||||||
|
#Write magic consumption rates to rom
|
||||||
|
for _,values in magic_cost.items():
|
||||||
|
rom.write_bytes(values[0], values[1])
|
||||||
|
|
||||||
#Set overflow items for progressive equipment
|
#Set overflow items for progressive equipment
|
||||||
rom.write_bytes(0x180090,
|
rom.write_bytes(0x180090,
|
||||||
[difficulty.progressive_sword_limit if world.swords[player] != 'swordless' else 0, overflow_replacement,
|
[difficulty.progressive_sword_limit if world.swords[player] != 'swordless' else 0, overflow_replacement,
|
||||||
@@ -990,7 +1015,7 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
rom.write_bytes(0x184000, [
|
rom.write_bytes(0x184000, [
|
||||||
# original_item, limit, replacement_item, filler
|
# original_item, limit, replacement_item, filler
|
||||||
0x12, 0x01, 0x35, 0xFF, # lamp -> 5 rupees
|
0x12, 0x01, 0x35, 0xFF, # lamp -> 5 rupees
|
||||||
0x51, 0x06, 0x52, 0xFF, # 6 +5 bomb upgrades -> +10 bomb upgrade
|
0x51, 0x00 if world.futuro[player] else 0x06, 0x31 if world.futuro[player] else 0x52, 0xFF, # 6 +5 bomb upgrades -> +10 bomb upgrade. If bomb-futuro, 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.retro[player] else 0x43, 0xFF, # silver arrows -> single arrow (red 20 in retro mode)
|
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
|
0x3E, difficulty.boss_heart_container_limit, 0x47, 0xff, # boss heart -> green 20
|
||||||
@@ -1103,8 +1128,12 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
rom.write_byte(0x180171, 0x01 if world.ganon_at_pyramid[player] else 0x00) # Enable respawning on pyramid after ganon death
|
rom.write_byte(0x180171, 0x01 if world.ganon_at_pyramid[player] else 0x00) # Enable respawning on pyramid after ganon death
|
||||||
rom.write_byte(0x180173, 0x01) # Bob is enabled
|
rom.write_byte(0x180173, 0x01) # Bob is enabled
|
||||||
rom.write_byte(0x180168, 0x08) # Spike Cave Damage
|
rom.write_byte(0x180168, 0x08) # Spike Cave Damage
|
||||||
rom.write_bytes(0x18016B, [0x04, 0x02, 0x01]) #Set spike cave and MM spike room Cape usage
|
if world.futuro[player]:
|
||||||
rom.write_bytes(0x18016E, [0x04, 0x08, 0x10]) #Set spike cave and MM spike room Cape usage
|
rom.write_bytes(0x18016B, [0x81, 0x04, 0x02]) # Set spike cave and MM spike room Byrna usage
|
||||||
|
rom.write_bytes(0x18016E, [0x01, 0x04, 0x08]) # Set spike cave and MM spike room Cape usage
|
||||||
|
else:
|
||||||
|
rom.write_bytes(0x18016B, [0x04, 0x02, 0x01]) # Set spike cave and MM spike room Byrna usage
|
||||||
|
rom.write_bytes(0x18016E, [0x04, 0x08, 0x10]) # Set spike cave and MM spike room Cape usage
|
||||||
rom.write_bytes(0x50563, [0x3F, 0x14]) # disable below ganon chest
|
rom.write_bytes(0x50563, [0x3F, 0x14]) # disable below ganon chest
|
||||||
rom.write_byte(0x50599, 0x00) # disable below ganon chest
|
rom.write_byte(0x50599, 0x00) # disable below ganon chest
|
||||||
rom.write_bytes(0xE9A5, [0x7E, 0x00, 0x24]) # disable below ganon chest
|
rom.write_bytes(0xE9A5, [0x7E, 0x00, 0x24]) # disable below ganon chest
|
||||||
@@ -1123,7 +1152,10 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
equip[0x36C] = 0x18
|
equip[0x36C] = 0x18
|
||||||
equip[0x36D] = 0x18
|
equip[0x36D] = 0x18
|
||||||
equip[0x379] = 0x68
|
equip[0x379] = 0x68
|
||||||
starting_max_bombs = 10
|
if world.futuro[player]:
|
||||||
|
starting_max_bombs = 0
|
||||||
|
else:
|
||||||
|
starting_max_bombs = 10
|
||||||
starting_max_arrows = 30
|
starting_max_arrows = 30
|
||||||
|
|
||||||
startingstate = CollectionState(world)
|
startingstate = CollectionState(world)
|
||||||
@@ -1259,6 +1291,12 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
else:
|
else:
|
||||||
raise RuntimeError(f'Unsupported item in starting equipment: {item.name}')
|
raise RuntimeError(f'Unsupported item in starting equipment: {item.name}')
|
||||||
|
|
||||||
|
# Set basepatch switches for the futuro mode
|
||||||
|
if world.futuro[player]:
|
||||||
|
rom.write_byte(0x18008D, 0x00)
|
||||||
|
else:
|
||||||
|
rom.write_byte(0x18008E, 0x01)
|
||||||
|
|
||||||
equip[0x343] = min(equip[0x343], starting_max_bombs)
|
equip[0x343] = min(equip[0x343], starting_max_bombs)
|
||||||
rom.write_byte(0x180034, starting_max_bombs)
|
rom.write_byte(0x180034, starting_max_bombs)
|
||||||
equip[0x377] = min(equip[0x377], starting_max_arrows)
|
equip[0x377] = min(equip[0x377], starting_max_arrows)
|
||||||
|
|||||||
Reference in New Issue
Block a user