Add cane-only modes

This commit is contained in:
2021-12-23 23:46:53 -08:00
parent b99fd4a820
commit 97e4a02bee
8 changed files with 262 additions and 69 deletions

View File

@@ -365,6 +365,19 @@ class World(object):
ret.prog_items['L2 Bombs', item.player] += 1 ret.prog_items['L2 Bombs', item.player] += 1
else: else:
ret.prog_items['L1 Bombs', item.player] += 1 ret.prog_items['L1 Bombs', item.player] += 1
elif 'Cane' in item.name:
if ret.has('L5 Cane', item.player):
pass
elif ret.has('L4 Cane', item.player):
ret.prog_items['L5 Cane', item.player] += 1
elif ret.has('L3 Cane', item.player):
ret.prog_items['L4 Cane', item.player] += 1
elif ret.has('L2 Cane', item.player):
ret.prog_items['L3 Cane', item.player] += 1
elif ret.has('L1 Cane', item.player):
ret.prog_items['L2 Cane', item.player] += 1
else:
ret.prog_items['L1 Cane', item.player] += 1
elif 'Glove' in item.name: elif 'Glove' in item.name:
if ret.has('Titans Mitts', item.player): if ret.has('Titans Mitts', item.player):
pass pass
@@ -393,6 +406,11 @@ class World(object):
ret.prog_items[item.name, item.player] += 1 ret.prog_items[item.name, item.player] += 1
elif item.advancement or item.smallkey or item.bigkey: elif item.advancement or item.smallkey or item.bigkey:
ret.prog_items[item.name, item.player] += 1 ret.prog_items[item.name, item.player] += 1
if item.name.endswith(' Cane'):
if ret.world.swords[item.player] == 'byrna' and not ret.has('Cane of Byrna', item.player):
ret.prog_items['Cane of Byrna', item.player] += 1
if ret.world.swords[item.player] == 'somaria' and not ret.has('Cane of Somaria', item.player):
ret.prog_items['Cane of Somaria', item.player] += 1
for item in self.itempool: for item in self.itempool:
soft_collect(item) soft_collect(item)
@@ -1239,8 +1257,8 @@ class CollectionState(object):
return basemagic >= smallmagic return basemagic >= smallmagic
def can_kill_most_things(self, player, enemies=5): def can_kill_most_things(self, player, enemies=5):
return (self.bomb_mode_check(player, 1) and return (self.special_weapon_check(player, 1) and
(self.has_blunt_weapon(player) or self.has_bomb_level(player, 1) (self.has_blunt_weapon(player) or self.has_special_weapon_level(player, 1)
or self.has('Cane of Somaria', player) or self.has('Cane of Somaria', player)
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)
@@ -1259,7 +1277,7 @@ class CollectionState(object):
# In the future, this can be used to check if the player starts without bombs # In the future, this can be used to check if the player starts without bombs
def can_use_bombs(self, player): def can_use_bombs(self, player):
if self.world.swords[player] == 'bombs': if self.world.swords[player] == 'bombs':
return self.has_bomb_level(player, 1) return self.has_special_weapon_level(player, 1)
return (not self.world.bombbag[player] or self.has('Bomb Upgrade (+10)', player)) and ((hasattr(self.world, "override_bomb_check") and self.world.override_bomb_check) or self.can_farm_bombs(player)) return (not self.world.bombbag[player] or self.has('Bomb Upgrade (+10)', player)) and ((hasattr(self.world, "override_bomb_check") and self.world.override_bomb_check) or self.can_farm_bombs(player))
def can_hit_crystal(self, player): def can_hit_crystal(self, player):
@@ -1316,23 +1334,41 @@ class CollectionState(object):
return False; return False;
return self.has_sword(player, level) return self.has_sword(player, level)
def has_bomb_level(self, player, level): def has_special_weapon_level(self, player, level):
if self.world.swords[player] != 'bombs': if self.world.swords[player] == 'bombs':
if level == 5:
return self.has('L5 Bombs', player)
elif level == 4:
return self.has('L5 Bombs', player) or self.has('L4 Bombs', player)
elif level == 3:
return self.has('L5 Bombs', player) or self.has('L4 Bombs', player) or self.has('L3 Bombs', player)
elif level == 2:
return self.has('L5 Bombs', player) or self.has('L4 Bombs', player) or self.has('L3 Bombs', player) or self.has('L2 Bombs', player)
elif level == 1:
return self.has('L5 Bombs', player) or self.has('L4 Bombs', player) or self.has('L3 Bombs', player) or self.has('L2 Bombs', player) or self.has('L1 Bombs', player)
return True
elif self.world.swords[player] in ['byrna', 'somaria', 'cane']:
if self.world.swords[player] == 'cane' and not self.has('Cane of Somaria', player) and not self.has('Cane of Byrna', player):
return False
if level == 5:
return self.has('L5 Cane', player)
elif level == 4:
return self.has('L5 Cane', player) or self.has('L4 Cane', player)
elif level == 3:
return self.has('L5 Cane', player) or self.has('L4 Cane', player) or self.has('L3 Cane', player)
elif level == 2:
return self.has('L5 Cane', player) or self.has('L4 Cane', player) or self.has('L3 Cane', player) or self.has('L2 Cane', player)
elif level == 1:
return self.has('L5 Cane', player) or self.has('L4 Cane', player) or self.has('L3 Cane', player) or self.has('L2 Cane', player) or self.has('L1 Cane', player)
return True
else:
return False return False
if level == 5:
return self.has('L5 Bombs', player)
elif level == 4:
return self.has('L5 Bombs', player) or self.has('L4 Bombs', player)
elif level == 3:
return self.has('L5 Bombs', player) or self.has('L4 Bombs', player) or self.has('L3 Bombs', player)
elif level == 2:
return self.has('L5 Bombs', player) or self.has('L4 Bombs', player) or self.has('L3 Bombs', player) or self.has('L2 Bombs', player)
elif level == 1:
return self.has('L5 Bombs', player) or self.has('L4 Bombs', player) or self.has('L3 Bombs', player) or self.has('L2 Bombs', player) or self.has('L1 Bombs', player)
return True
def bomb_mode_check(self, player, level): def special_weapon_check(self, player, level):
return self.world.swords[player] != 'bombs' or self.has_bomb_level(player, level) if self.world.swords[player] in ['bombs', 'byrna', 'somaria', 'cane']:
return self.has_special_weapon_level(player, level)
else:
return True
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]
@@ -1375,7 +1411,7 @@ class CollectionState(object):
return False return False
def can_use_medallions(self, player): def can_use_medallions(self, player):
return self.has_sword(player) or self.world.swords[player] == 'bombs' return self.has_sword(player) or self.world.swords[player] in ['bombs', 'byrna', 'somaria', 'cane']
def has_blunt_weapon(self, player): def has_blunt_weapon(self, player):
return self.has_real_sword(player) or self.has('Hammer', player) return self.has_real_sword(player) or self.has('Hammer', player)
@@ -1491,6 +1527,24 @@ class CollectionState(object):
else: else:
self.prog_items['L1 Bombs', item.player] += 1 self.prog_items['L1 Bombs', item.player] += 1
changed = True changed = True
elif 'Cane' in item.name:
if self.has('L5 Cane', item.player):
pass
elif self.has('L4 Cane', item.player):
self.prog_items['L5 Cane', item.player] += 1
changed = True
elif self.has('L3 Cane', item.player):
self.prog_items['L4 Cane', item.player] += 1
changed = True
elif self.has('L2 Cane', item.player):
self.prog_items['L3 Cane', item.player] += 1
changed = True
elif self.has('L1 Cane', item.player):
self.prog_items['L2 Cane', item.player] += 1
changed = True
else:
self.prog_items['L1 Cane', item.player] += 1
changed = True
elif 'Glove' in item.name: elif 'Glove' in item.name:
if self.has('Titans Mitts', item.player): if self.has('Titans Mitts', item.player):
pass pass
@@ -1541,6 +1595,13 @@ class CollectionState(object):
elif event or item.advancement: elif event or item.advancement:
self.prog_items[item.name, item.player] += 1 self.prog_items[item.name, item.player] += 1
changed = True changed = True
if item.name.endswith(' Cane'):
if self.world.swords[item.player] == 'byrna' and not self.has('Cane of Byrna', item.player):
self.prog_items['Cane of Byrna', item.player] += 1
changed = True
if self.world.swords[item.player] == 'somaria' and not self.has('Cane of Somaria', item.player):
self.prog_items['Cane of Somaria', item.player] += 1
changed = True
self.stale[item.player] = True self.stale[item.player] = True
@@ -1576,6 +1637,19 @@ class CollectionState(object):
to_remove = 'L1 Bombs' to_remove = 'L1 Bombs'
else: else:
to_remove = None to_remove = None
elif 'Cane' in to_remove:
if self.has('L5 Cane', item.player):
to_remove = 'L5 Cane'
elif self.has('L4 Cane', item.player):
to_remove = 'L4 Cane'
elif self.has('L3 Cane', item.player):
to_remove = 'L3 Cane'
elif self.has('L2 Cane', item.player):
to_remove = 'L2 Cane'
elif self.has('L1 Cane', item.player):
to_remove = 'L1 Cane'
else:
to_remove = None
elif 'Glove' in item.name: elif 'Glove' in item.name:
if self.has('Titans Mitts', item.player): if self.has('Titans Mitts', item.player):
to_remove = 'Titans Mitts' to_remove = 'Titans Mitts'
@@ -1601,7 +1675,15 @@ class CollectionState(object):
to_remove = None to_remove = None
if to_remove is not None: if to_remove is not None:
if to_remove.endswith(' Cane') and not self.has('L5 Cane', item.player) and not self.has('L4 Cane', item.player) and not self.has('L3 Cane', item.player) and not self.has('L2 Cane', item.player) and not self.has('L1 Cane', item.player):
if self.world.swords[item.player] == 'byrna':
self.prog_items['Cane of Byrna', item.player] -= 1
if self.prog_items['Cane of Byrna', item.player] < 1:
del (self.prog_items['Cane of Byrna', item.player])
if self.world.swords[item.player] == 'somaria':
self.prog_items['Cane of Somaria', item.player] -= 1
if self.prog_items['Cane of Somaria', item.player] < 1:
del (self.prog_items['Cane of Somaria', item.player])
self.prog_items[to_remove, item.player] -= 1 self.prog_items[to_remove, item.player] -= 1
if self.prog_items[to_remove, item.player] < 1: if self.prog_items[to_remove, item.player] < 1:
del (self.prog_items[to_remove, item.player]) del (self.prog_items[to_remove, item.player])
@@ -2940,8 +3022,8 @@ class Spoiler(object):
'experimental': self.world.experimental, 'experimental': self.world.experimental,
'keydropshuffle': self.world.keydropshuffle, 'keydropshuffle': self.world.keydropshuffle,
'shopsanity': self.world.shopsanity, 'shopsanity': self.world.shopsanity,
'triforcegoal': self.world.treasure_hunt_count, 'triforcegoal': self.world.treasure_hunt_count,
'triforcepool': self.world.treasure_hunt_total, 'triforcepool': self.world.treasure_hunt_total,
'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)} 'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)}
} }
@@ -3320,7 +3402,7 @@ er_mode = {"vanilla": 0, "simple": 1, "restricted": 2, "full": 3, "lite": 4, "le
# byte 1: LLLW WSSS (logic, mode, sword) # byte 1: LLLW WSSS (logic, mode, sword)
logic_mode = {"noglitches": 0, "minorglitches": 1, "nologic": 2, "owglitches": 3, "majorglitches": 4} logic_mode = {"noglitches": 0, "minorglitches": 1, "nologic": 2, "owglitches": 3, "majorglitches": 4}
world_mode = {"open": 0, "standard": 1, "inverted": 2} world_mode = {"open": 0, "standard": 1, "inverted": 2}
sword_mode = {"random": 0, "assured": 1, "swordless": 2, "vanilla": 3, "bombs": 4, "pseudo": 5, "assured_pseudo": 6} sword_mode = {"random": 0, "assured": 1, "swordless": 2, "vanilla": 3, "bombs": 4, "pseudo": 5, "assured_pseudo": 5, "byrna": 6, "somaria": 6, "cane": 6}
# byte 2: GGGD DFFH (goal, diff, item_func, hints) # byte 2: GGGD DFFH (goal, diff, item_func, hints)
goal_mode = {"ganon": 0, "pedestal": 1, "dungeons": 2, "triforcehunt": 3, "crystals": 4} goal_mode = {"ganon": 0, "pedestal": 1, "dungeons": 2, "triforcehunt": 3, "crystals": 4}

View File

@@ -16,7 +16,7 @@ def BossFactory(boss, player):
def ArmosKnightsDefeatRule(state, player): def ArmosKnightsDefeatRule(state, player):
# Magic amounts are probably a bit overkill # Magic amounts are probably a bit overkill
return (state.bomb_mode_check(player, 1) and return (state.special_weapon_check(player, 1) and
(state.has_blunt_weapon(player) or (state.has_blunt_weapon(player) or
state.can_shoot_arrows(player) or state.can_shoot_arrows(player) or
(state.has('Cane of Somaria', player) and state.can_extend_magic(player, 10)) or (state.has('Cane of Somaria', player) and state.can_extend_magic(player, 10)) or
@@ -25,38 +25,38 @@ def ArmosKnightsDefeatRule(state, player):
(state.has('Fire Rod', player) and state.can_extend_magic(player, 32)) or (state.has('Fire Rod', player) and state.can_extend_magic(player, 32)) or
state.has('Blue Boomerang', player) or state.has('Blue Boomerang', player) or
state.has('Red Boomerang', player) or state.has('Red Boomerang', player) or
state.has_bomb_level(player, 1))) state.has_special_weapon_level(player, 1)))
def LanmolasDefeatRule(state, player): def LanmolasDefeatRule(state, player):
return (state.bomb_mode_check(player, 1) and return (state.special_weapon_check(player, 1) and
(state.has_blunt_weapon(player) or (state.has_blunt_weapon(player) or
state.has('Fire Rod', player) or state.has('Fire Rod', player) or
state.has('Ice Rod', player) or state.has('Ice Rod', player) or
state.has('Cane of Somaria', player) or state.has('Cane of Somaria', player) or
state.has('Cane of Byrna', player) or state.has('Cane of Byrna', player) or
state.can_shoot_arrows(player) or state.can_shoot_arrows(player) or
state.has_bomb_level(player, 1))) state.has_special_weapon_level(player, 1)))
def MoldormDefeatRule(state, player): def MoldormDefeatRule(state, player):
return (state.bomb_mode_check(player, 1) and return (state.special_weapon_check(player, 1) and
(state.has_blunt_weapon(player) or state.has_bomb_level(player, 1))) (state.has_blunt_weapon(player) or state.has_special_weapon_level(player, 1)))
def HelmasaurKingDefeatRule(state, player): def HelmasaurKingDefeatRule(state, player):
return (state.bomb_mode_check(player, 2) and return (state.special_weapon_check(player, 2) and
(state.has('Hammer', player) or state.can_use_bombs(player)) and (state.has('Hammer', player) or state.can_use_bombs(player)) and
(state.has_real_sword(player) or state.can_shoot_arrows(player) or state.has_bomb_level(player, 2))) (state.has_real_sword(player) or state.can_shoot_arrows(player) or state.has_special_weapon_level(player, 2)))
def ArrghusDefeatRule(state, player): def ArrghusDefeatRule(state, player):
if not state.has('Hookshot', player): if not state.has('Hookshot', player):
return False return False
if not state.bomb_mode_check(player, 2): if not state.special_weapon_check(player, 2):
return False return False
# TODO: ideally we would have a check for bow and silvers, which combined with the # TODO: ideally we would have a check for bow and silvers, which combined with the
# hookshot is enough. This is not coded yet because the silvers that only work in pyramid feature # hookshot is enough. This is not coded yet because the silvers that only work in pyramid feature
# makes this complicated # makes this complicated
if state.has_blunt_weapon(player) or state.has_bomb_level(player, 2): if state.has_blunt_weapon(player) or state.has_special_weapon_level(player, 2):
return True return True
return ((state.has('Fire Rod', player) and (state.can_shoot_arrows(player) or state.can_extend_magic(player, 12))) or #assuming mostly gitting two puff with one shot return ((state.has('Fire Rod', player) and (state.can_shoot_arrows(player) or state.can_extend_magic(player, 12))) or #assuming mostly gitting two puff with one shot
@@ -64,7 +64,7 @@ def ArrghusDefeatRule(state, player):
def MothulaDefeatRule(state, player): def MothulaDefeatRule(state, player):
return (state.bomb_mode_check(player, 1) and return (state.special_weapon_check(player, 1) and
(state.has_blunt_weapon(player) or (state.has_blunt_weapon(player) or
(state.has('Fire Rod', player) and state.can_extend_magic(player, 10)) or (state.has('Fire Rod', player) and state.can_extend_magic(player, 10)) or
# TODO: Not sure how much (if any) extend magic is needed for these two, since they only apply # TODO: Not sure how much (if any) extend magic is needed for these two, since they only apply
@@ -72,15 +72,15 @@ def MothulaDefeatRule(state, player):
(state.has('Cane of Somaria', player) and state.can_extend_magic(player, 16)) or (state.has('Cane of Somaria', player) and state.can_extend_magic(player, 16)) or
(state.has('Cane of Byrna', player) and state.can_extend_magic(player, 16)) or (state.has('Cane of Byrna', player) and state.can_extend_magic(player, 16)) or
state.can_get_good_bee(player) or state.can_get_good_bee(player) or
state.has_bomb_level(player, 1))) state.has_special_weapon_level(player, 1)))
def BlindDefeatRule(state, player): def BlindDefeatRule(state, player):
return (state.bomb_mode_check(player, 1) and return (state.special_weapon_check(player, 1) and
(state.has_blunt_weapon(player) or state.has('Cane of Somaria', player) or (state.has_blunt_weapon(player) or state.has('Cane of Somaria', player) or
state.has('Cane of Byrna', player) or state.has_bomb_level(player, 1))) state.has('Cane of Byrna', player) or state.has_special_weapon_level(player, 1)))
def KholdstareDefeatRule(state, player): def KholdstareDefeatRule(state, player):
return (state.bomb_mode_check(player, 2) and return (state.special_weapon_check(player, 2) and
( (
state.has('Fire Rod', player) or state.has('Fire Rod', player) or
( (
@@ -90,7 +90,7 @@ def KholdstareDefeatRule(state, player):
) )
) and ) and
( (
state.has_bomb_level(player, 2) or state.has_blunt_weapon(player) or state.has_special_weapon_level(player, 2) or state.has_blunt_weapon(player) or
(state.has('Fire Rod', player) and state.can_extend_magic(player, 20)) or (state.has('Fire Rod', player) and state.can_extend_magic(player, 20)) or
# FIXME: this actually only works for the vanilla location for swordless # FIXME: this actually only works for the vanilla location for swordless
( (
@@ -102,21 +102,21 @@ def KholdstareDefeatRule(state, player):
)) ))
def VitreousDefeatRule(state, player): def VitreousDefeatRule(state, player):
return (state.bomb_mode_check(player, 2) and return (state.special_weapon_check(player, 2) and
(state.can_shoot_arrows(player) or state.has_blunt_weapon(player) or (state.can_shoot_arrows(player) or state.has_blunt_weapon(player) or
state.has_bomb_level(player, 2))) state.has_special_weapon_level(player, 2)))
def TrinexxDefeatRule(state, player): def TrinexxDefeatRule(state, player):
if not (state.has('Fire Rod', player) and state.has('Ice Rod', player)): if not (state.has('Fire Rod', player) and state.has('Ice Rod', player)):
return False return False
if not state.bomb_mode_check(player, 2): if not state.special_weapon_check(player, 2):
return False return False
return (state.has('Hammer', player) or return (state.has('Hammer', player) or
state.has_real_sword(player, 3) or state.has_real_sword(player, 3) or
state.has_bomb_level(player, 4) or state.has_special_weapon_level(player, 4) or
((state.has_real_sword(player, 2) or state.has_bomb_level(player, 3)) ((state.has_real_sword(player, 2) or state.has_special_weapon_level(player, 3))
and state.can_extend_magic(player, 16)) or and state.can_extend_magic(player, 16)) or
((state.has_real_sword(player) or state.has_bomb_level(player, 2)) ((state.has_real_sword(player) or state.has_special_weapon_level(player, 2))
and state.can_extend_magic(player, 32))) and state.can_extend_magic(player, 32)))
def AgahnimDefeatRule(state, player): def AgahnimDefeatRule(state, player):

View File

@@ -34,7 +34,7 @@ normalfinal25extra = ['Rupees (20)'] * 23 + ['Rupees (5)'] * 2
Difficulty = namedtuple('Difficulty', Difficulty = namedtuple('Difficulty',
['baseitems', 'bottles', 'bottle_count', 'same_bottle', 'progressiveshield', ['baseitems', 'bottles', 'bottle_count', 'same_bottle', 'progressiveshield',
'basicshield', 'progressivearmor', 'basicarmor', 'swordless', 'bombs_only', 'basicshield', 'progressivearmor', 'basicarmor', 'swordless', 'bombs_only', 'cane_only',
'progressivesword', 'basicsword', 'basicbow', 'timedohko', 'timedother', 'progressivesword', 'basicsword', 'basicbow', 'timedohko', 'timedother',
'retro', 'bombbag', 'retro', 'bombbag',
'extras', 'progressive_sword_limit', 'progressive_shield_limit', 'extras', 'progressive_sword_limit', 'progressive_shield_limit',
@@ -55,6 +55,7 @@ difficulties = {
basicarmor = ['Blue Mail', 'Red Mail'], basicarmor = ['Blue Mail', 'Red Mail'],
swordless = ['Rupees (20)'] * 4, swordless = ['Rupees (20)'] * 4,
bombs_only = ['Progressive Bombs'] * 4, bombs_only = ['Progressive Bombs'] * 4,
cane_only = ['Progressive Cane'] * 3 + ['Rupees (20)'],
progressivesword = ['Progressive Sword'] * 4, progressivesword = ['Progressive Sword'] * 4,
basicsword = ['Fighter Sword', 'Master Sword', 'Tempered Sword', 'Golden Sword'], basicsword = ['Fighter Sword', 'Master Sword', 'Tempered Sword', 'Golden Sword'],
basicbow = ['Bow', 'Silver Arrows'], basicbow = ['Bow', 'Silver Arrows'],
@@ -82,6 +83,7 @@ difficulties = {
basicarmor = ['Progressive Armor'] * 2, # neither will count basicarmor = ['Progressive Armor'] * 2, # neither will count
swordless = ['Rupees (20)'] * 4, swordless = ['Rupees (20)'] * 4,
bombs_only = ['Progressive Bombs'] * 4, bombs_only = ['Progressive Bombs'] * 4,
cane_only = ['Progressive Cane'] * 3 + ['Rupees (20)'],
progressivesword = ['Progressive Sword'] * 4, progressivesword = ['Progressive Sword'] * 4,
basicsword = ['Fighter Sword', 'Master Sword', 'Master Sword', 'Tempered Sword'], basicsword = ['Fighter Sword', 'Master Sword', 'Master Sword', 'Tempered Sword'],
basicbow = ['Bow'] * 2, basicbow = ['Bow'] * 2,
@@ -109,6 +111,7 @@ difficulties = {
basicarmor = ['Progressive Armor'] * 2, # neither will count basicarmor = ['Progressive Armor'] * 2, # neither will count
swordless = ['Rupees (20)'] * 4, swordless = ['Rupees (20)'] * 4,
bombs_only = ['Progressive Bombs'] * 4, bombs_only = ['Progressive Bombs'] * 4,
cane_only = ['Progressive Cane'] * 3 + ['Rupees (20)'],
progressivesword = ['Progressive Sword'] * 4, progressivesword = ['Progressive Sword'] * 4,
basicsword = ['Fighter Sword', 'Fighter Sword', 'Master Sword', 'Master Sword'], basicsword = ['Fighter Sword', 'Fighter Sword', 'Master Sword', 'Master Sword'],
basicbow = ['Bow'] * 2, basicbow = ['Bow'] * 2,
@@ -283,8 +286,7 @@ def generate_itempool(world, player):
for item in precollected_items: for item in precollected_items:
world.push_precollected(ItemFactory(item, player)) world.push_precollected(ItemFactory(item, player))
if (world.mode[player] == 'standard' and not (world.state.has_bomb_level(player, 1) if world.swords[player] else world.state.has_blunt_weapon(player)) if world.mode[player] == 'standard' and not (world.state.has_special_weapon_level(player, 1) if world.swords[player] in ['bombs', 'byrna', 'somaria', 'cane'] else world.state.has_blunt_weapon(player)):
and not world.state.has_bomb_level(player, 1)):
if world.swords[player] == 'bombs' and "Link's Uncle" not in placed_items: if world.swords[player] == 'bombs' and "Link's Uncle" not in placed_items:
possible_weapons = [] possible_weapons = []
for item in pool: for item in pool:
@@ -293,6 +295,22 @@ def generate_itempool(world, player):
starting_weapon = random.choice(possible_weapons) starting_weapon = random.choice(possible_weapons)
placed_items["Link's Uncle"] = starting_weapon placed_items["Link's Uncle"] = starting_weapon
pool.remove(starting_weapon) pool.remove(starting_weapon)
elif world.swords[player] in ['byrna', 'somaria'] and "Link's Uncle" not in placed_items:
possible_weapons = []
for item in pool:
if item in ['Progressive Cane', 'L1 Cane', 'L2 Cane', 'L3 Cane', 'L4 Cane', 'L5 Cane']:
possible_weapons.append(item)
starting_weapon = random.choice(possible_weapons)
placed_items["Link's Uncle"] = starting_weapon
pool.remove(starting_weapon)
elif world.swords[player] in ['cane'] and "Link's Uncle" not in placed_items:
possible_weapons = []
for item in pool:
if item in ['Cane of Byrna', 'Cane of Somaria']:
possible_weapons.append(item)
starting_weapon = random.choice(possible_weapons)
placed_items["Link's Uncle"] = starting_weapon
pool.remove(starting_weapon)
elif "Link's Uncle" not in placed_items: elif "Link's Uncle" not in placed_items:
found_sword = False found_sword = False
found_bow = False found_bow = False
@@ -866,6 +884,14 @@ def get_pool_core(progressive, shuffle, difficulty, treasure_hunt_total, timer,
pool.extend(diff.swordless) pool.extend(diff.swordless)
elif swords == 'bombs': elif swords == 'bombs':
pool.extend(diff.bombs_only) pool.extend(diff.bombs_only)
elif swords == 'byrna':
pool = [item.replace('Cane of Byrna', 'Progressive Cane') for item in pool]
pool.extend(diff.cane_only)
elif swords == 'somaria':
pool = [item.replace('Cane of Somaria', 'Progressive Cane') for item in pool]
pool.extend(diff.cane_only)
elif swords == 'cane':
pool.extend(diff.cane_only)
elif swords == 'vanilla': elif swords == 'vanilla':
swords_to_use = diff.progressivesword.copy() if want_progressives() else diff.basicsword.copy() swords_to_use = diff.progressivesword.copy() if want_progressives() else diff.basicsword.copy()
random.shuffle(swords_to_use) random.shuffle(swords_to_use)
@@ -974,7 +1000,7 @@ def make_custom_item_pool(progressive, shuffle, difficulty, timer, goal, mode, s
itemtotal = itemtotal + customitemarray["generickeys"] itemtotal = itemtotal + customitemarray["generickeys"]
customitems = [ customitems = [
"Bow", "Silver Arrows", "Blue Boomerang", "Red Boomerang", "Hookshot", "Mushroom", "Magic Powder", "Fire Rod", "Ice Rod", "Bombos", "Ether", "Quake", "Lamp", "Hammer", "Shovel", "Ocarina", "Bug Catching Net", "Book of Mudora", "Cane of Somaria", "Cane of Byrna", "Cape", "Pegasus Boots", "Power Glove", "Titans Mitts", "Progressive Glove", "Flippers", "Piece of Heart", "Boss Heart Container", "Sanctuary Heart Container", "Master Sword", "Tempered Sword", "Golden Sword", "L1 Bombs", "L2 Bombs", "L3 Bombs", "L4 Bombs", "L5 Bombs", "Progressive Bombs", "Blue Shield", "Red Shield", "Mirror Shield", "Progressive Shield", "Blue Mail", "Red Mail", "Progressive Armor", "Magic Upgrade (1/2)", "Magic Upgrade (1/4)", "Bomb Upgrade (+5)", "Bomb Upgrade (+10)", "Arrow Upgrade (+5)", "Arrow Upgrade (+10)", "Single Arrow", "Arrows (10)", "Single Bomb", "Bombs (3)", "Rupee (1)", "Rupees (5)", "Rupees (20)", "Rupees (50)", "Rupees (100)", "Rupees (300)", "Rupoor", "Blue Clock", "Green Clock", "Red Clock", "Progressive Bow", "Bombs (10)", "Triforce Piece", "Triforce" "Bow", "Silver Arrows", "Blue Boomerang", "Red Boomerang", "Hookshot", "Mushroom", "Magic Powder", "Fire Rod", "Ice Rod", "Bombos", "Ether", "Quake", "Lamp", "Hammer", "Shovel", "Ocarina", "Bug Catching Net", "Book of Mudora", "Cane of Somaria", "Cane of Byrna", "Cape", "Pegasus Boots", "Power Glove", "Titans Mitts", "Progressive Glove", "Flippers", "Piece of Heart", "Boss Heart Container", "Sanctuary Heart Container", "Master Sword", "Tempered Sword", "Golden Sword", "L1 Bombs", "L2 Bombs", "L3 Bombs", "L4 Bombs", "L5 Bombs", "Progressive Bombs", "L1 Cane", "L2 Cane", "L3 Cane", "L4 Cane", "L5 Cane", "Progressive Cane", "Blue Shield", "Red Shield", "Mirror Shield", "Progressive Shield", "Blue Mail", "Red Mail", "Progressive Armor", "Magic Upgrade (1/2)", "Magic Upgrade (1/4)", "Bomb Upgrade (+5)", "Bomb Upgrade (+10)", "Arrow Upgrade (+5)", "Arrow Upgrade (+10)", "Single Arrow", "Arrows (10)", "Single Bomb", "Bombs (3)", "Rupee (1)", "Rupees (5)", "Rupees (20)", "Rupees (50)", "Rupees (100)", "Rupees (300)", "Rupoor", "Blue Clock", "Green Clock", "Red Clock", "Progressive Bow", "Bombs (10)", "Triforce Piece", "Triforce"
] ]
for customitem in customitems: for customitem in customitems:
pool.extend([customitem] * customitemarray[get_custom_array_key(customitem)]) pool.extend([customitem] * customitemarray[get_custom_array_key(customitem)])
@@ -1049,7 +1075,7 @@ def test():
for goal in ['ganon', 'triforcehunt', 'pedestal']: for goal in ['ganon', 'triforcehunt', 'pedestal']:
for timer in ['none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown']: for timer in ['none', 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown']:
for mode in ['open', 'standard', 'inverted', 'retro']: for mode in ['open', 'standard', 'inverted', 'retro']:
for swords in ['random', 'assured', 'swordless', 'vanilla', 'bombs']: for swords in ['random', 'assured', 'swordless', 'vanilla', 'bombs', 'byrna', 'somaria', 'cane']:
for progressive in ['on', 'off']: for progressive in ['on', 'off']:
for shuffle in ['vanilla', 'full', 'crossed', 'insanity']: for shuffle in ['vanilla', 'full', 'crossed', 'insanity']:
for logic in ['noglitches', 'minorglitches', 'owglitches', 'nologic']: for logic in ['noglitches', 'minorglitches', 'owglitches', 'nologic']:

View File

@@ -168,10 +168,16 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche
'Bee Trap': (False, False, None, 0xB0, 50, 'We will sting your face a whole lot!', 'and the sting buddies', 'the beekeeper kid', 'insects for sale', 'shroom pollenation', 'bottle boy has mad bees again', 'friendship'), 'Bee Trap': (False, False, None, 0xB0, 50, 'We will sting your face a whole lot!', 'and the sting buddies', 'the beekeeper kid', 'insects for sale', 'shroom pollenation', 'bottle boy has mad bees again', 'friendship'),
'L1 Bombs': (True, False, 'SwordBomb', 0xB1, 50, 'Some basic\nexplosives\nrest here!', 'the basic grenades', 'the bomb-holding kid', 'booms for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'basic bombs'), 'L1 Bombs': (True, False, 'SwordBomb', 0xB1, 50, 'Some basic\nexplosives\nrest here!', 'the basic grenades', 'the bomb-holding kid', 'booms for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'basic bombs'),
'L2 Bombs': (True, False, 'SwordBomb', 0xB2, 100, 'Some decent\nexplosives\nrest here!', 'the decent grenades', 'the bomb-holding kid', 'better booms for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'fancy bombs'), 'L2 Bombs': (True, False, 'SwordBomb', 0xB2, 100, 'Some decent\nexplosives\nrest here!', 'the decent grenades', 'the bomb-holding kid', 'better booms for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'fancy bombs'),
'L3 Bombs': (True, False, 'SwordBomb', 0xB3, 150, 'Some good\nexplosives\nrest here!', 'the good grenades sword', 'the bomb-holding kid', 'better booms for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'fancy bombs'), 'L3 Bombs': (True, False, 'SwordBomb', 0xB3, 150, 'Some good\nexplosives\nrest here!', 'the good grenades', 'the bomb-holding kid', 'better booms for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'fancy bombs'),
'L4 Bombs': (True, False, 'SwordBomb', 0xB4, 200, 'The golden\nexplosives\nrest here!', 'the golden grenades', 'the bomb-holding kid', 'better booms for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'fancy bombs'), 'L4 Bombs': (True, False, 'SwordBomb', 0xB4, 200, 'The golden\nexplosives\nrest here!', 'the golden grenades', 'the bomb-holding kid', 'better booms for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'fancy bombs'),
'L5 Bombs': (True, False, 'SwordBomb', 0xB5, 200, 'The golden\nexplosives\nrest here!', 'the golden grenades', 'the bomb-holding kid', 'better booms sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'fancy bombs'), 'L5 Bombs': (True, False, 'SwordBomb', 0xB5, 200, 'The golden\nexplosives\nrest here!', 'the golden grenades', 'the bomb-holding kid', 'better booms for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'fancy bombs'),
'Progressive Bombs': (True, False, 'SwordBomb', 0xB6, 200, 'throw more\npowerful\nexplosives', 'the unknown grenades', 'the bomb-holding kid', 'better booms sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'fancy bombs'), 'Progressive Bombs': (True, False, 'SwordBomb', 0xB6, 200, 'throw more\npowerful\nexplosives', 'the unknown grenades', 'the bomb-holding kid', 'better booms for sale', 'blend fungus into bombs', '\'splosion boy explodes again', 'fancy bombs'),
'L1 Cane': (True, False, 'SwordCane', 0xB7, 50, 'A basic\nstick\nrests here!', 'the basic stick', 'the stick-holding kid', 'stick for sale', 'fungus into stick', 'cane boy improves again', 'basic cane'),
'L2 Cane': (True, False, 'SwordCane', 0xB8, 100, 'A decent\nstick\nrests here!', 'the decent stick', 'the stick-holding kid', 'better stick for sale', 'fungus into stick', 'cane boy improves again', 'fancy cane'),
'L3 Cane': (True, False, 'SwordCane', 0xB9, 150, 'A good\nstick\nrests here!', 'the good stick', 'the stick-holding kid', 'better stick for sale', 'fungus into stick', 'cane boy improves again', 'fancy cane'),
'L4 Cane': (True, False, 'SwordCane', 0xBA, 200, 'A golden\nstick\nrests here!', 'the golden stick', 'the stick-holding kid', 'better stick for sale', 'fungus into stick', 'cane boy improves again', 'fancy cane'),
'L5 Cane': (True, False, 'SwordCane', 0xBB, 200, 'A golden\nstick\nrests here!', 'the golden stick', 'the stick-holding kid', 'better stick for sale', 'fungus into stick', 'cane boy improves again', 'fancy cane'),
'Progressive Cane': (True, False, 'SwordCane', 0xBC, 200, 'a better\nstick\nrests here!', 'the unknown stick', 'the stick-holding kid', 'better stick for sale', 'fungus into stick', 'cane boy improves again', 'fancy cane'),
'Red Potion': (False, False, None, 0x2E, 150, 'Hearty red goop!', 'and the red goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has red goo again', 'a red potion'), 'Red Potion': (False, False, None, 0x2E, 150, 'Hearty red goop!', 'and the red goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has red goo again', 'a red potion'),
'Green Potion': (False, False, None, 0x2F, 60, 'Refreshing green goop!', 'and the green goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has green goo again', 'a green potion'), 'Green Potion': (False, False, None, 0x2F, 60, 'Refreshing green goop!', 'and the green goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has green goo again', 'a green potion'),
'Blue Potion': (False, False, None, 0x30, 160, 'Delicious blue goop!', 'and the blue goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has blue goo again', 'a blue potion'), 'Blue Potion': (False, False, None, 0x30, 160, 'Delicious blue goop!', 'and the blue goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has blue goo again', 'a blue potion'),

78
Rom.py
View File

@@ -33,7 +33,7 @@ from source.classes.SFX import randomize_sfx
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '7c1873254dcd5fb8b18934d806cd1949' RANDOMIZERBASEHASH = 'b61fd3ea2d9c4c0465317052fa30a721'
class JsonRom(object): class JsonRom(object):
@@ -1006,7 +1006,10 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
TRIFORCE_PIECE = ItemFactory('Triforce Piece', player).code TRIFORCE_PIECE = ItemFactory('Triforce Piece', player).code
GREEN_CLOCK = ItemFactory('Green Clock', player).code GREEN_CLOCK = ItemFactory('Green Clock', player).code
rom.write_byte(0x18004F, 0x01) # Byrna Invulnerability: on if world.swords[player] in ['byrna', 'cane']:
rom.write_byte(0x18004F, 0x00) # Byrna Invulnerability: off
else:
rom.write_byte(0x18004F, 0x01) # Byrna Invulnerability: on
# handle difficulty_adjustments # handle difficulty_adjustments
if world.difficulty_adjustments[player] == 'hard': if world.difficulty_adjustments[player] == 'hard':
@@ -1060,8 +1063,6 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
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]) rom.write_bytes(0x3ADA7, [0x04, 0x08, 0x10])
# Byrna Invulnerability: on
rom.write_byte(0x18004F, 0x01)
#Enable catching fairies #Enable catching fairies
rom.write_byte(0x34FD6, 0xF0) rom.write_byte(0x34FD6, 0xF0)
# Rupoor negative value # Rupoor negative value
@@ -1267,6 +1268,64 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
rom.write_bytes(0x118188, credits_string_bot("TEMPERED BOMBS")) rom.write_bytes(0x118188, credits_string_bot("TEMPERED BOMBS"))
rom.write_bytes(0x1181A6, credits_string_top("GOLD BOMBS")) rom.write_bytes(0x1181A6, credits_string_top("GOLD BOMBS"))
rom.write_bytes(0x1181C4, credits_string_bot("GOLD BOMBS")) rom.write_bytes(0x1181C4, credits_string_bot("GOLD BOMBS"))
elif world.swords[player] in ['byrna', 'somaria', 'cane']:
rom.write_byte(0x180040, 0x01) # open curtains
rom.write_byte(0x180041, 0x02) # swordless medallions (always)
rom.write_byte(0x180034, 0x00) # starting max bombs = 0
# remove magic cost of cane(s)
if world.swords[player] in ['byrna', 'cane']:
rom.write_bytes(0x045C42, [0x00, 0x00, 0x00])
rom.write_bytes(0x045CC7, [0xEA, 0xEA])
rom.write_byte(0x045CCD, 0x81)
rom.write_bytes(0x03B088, [0x00, 0x00, 0x00])
rom.write_bytes(0x03B0A8, [0xEA, 0xEA])
rom.write_byte(0x03B0AE, 0x81)
rom.write_bytes(0x18016B, [0x00, 0x00, 0x00])
if world.swords[player] in ['somaria', 'cane']:
rom.write_bytes(0x03B07C, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
rom.write_bytes(0x03B0A8, [0xEA, 0xEA])
rom.write_byte(0x03B0AE, 0x81)
if world.swords[player] == 'byrna':
rom.write_byte(0x18002F, 0x03)
colr = 0x2C
elif world.swords[player] == 'somaria':
rom.write_byte(0x18002F, 0x04)
colr = 0x24
elif world.swords[player] == 'cane':
rom.write_byte(0x18002F, 0x05)
colr = 0x28
spritedata = [
0xF5, 0x20, 0xF5, 0x20, 0xF5, 0x20, 0xF5, 0x20,
0xDC, colr, 0xDD, colr, 0xEC, colr, 0x17, colr,
0xDC, colr, 0xDD, colr, 0xEC, colr, 0x18, colr,
0xDC, colr, 0xDD, colr, 0xEC, colr, 0x19, colr,
0xDC, colr, 0xDD, colr, 0xEC, colr, 0x1A, colr,
0xDC, colr, 0xDD, colr, 0xEC, colr, 0x1B, colr,
0xF5, 0x20, 0xF5, 0x20, 0xF5, 0x20, 0xF5, 0x20,
0xDC, colr, 0xDD, colr, 0xEC, colr, 0x17, colr,
0xDC, colr, 0xDD, colr, 0xEC, colr, 0x18, colr,
0xDC, colr, 0xDD, colr, 0xEC, colr, 0x19, colr,
0xDC, colr, 0xDD, colr, 0xEC, colr, 0x1A, colr,
0xDC, colr, 0xDD, colr, 0xEC, colr, 0x1B, colr,
];
rom.write_bytes(0x06FC51, spritedata)
# update sword references in credits to cane
rom.write_bytes(0x11807A, credits_string_top("FIRST CANE "))
rom.write_bytes(0x118098, credits_string_bot("FIRST CANE "))
rom.write_bytes(0x1180B6, credits_string_top("CANELESS "))
rom.write_bytes(0x1180D4, credits_string_bot("CANELESS "))
rom.write_bytes(0x1180F2, credits_string_top("FIGHTER'S CANE "))
rom.write_bytes(0x118110, credits_string_bot("FIGHTER'S CANE "))
rom.write_bytes(0x11812E, credits_string_top("MASTER CANE "))
rom.write_bytes(0x11814C, credits_string_bot("MASTER CANE "))
rom.write_bytes(0x11816A, credits_string_top("TEMPERED CANE "))
rom.write_bytes(0x118188, credits_string_bot("TEMPERED CANE "))
rom.write_bytes(0x1181A6, credits_string_top("GOLD CANE "))
rom.write_bytes(0x1181C4, credits_string_bot("GOLD CANE "))
# set up clocks for timed modes # set up clocks for timed modes
if world.shuffle[player] == 'vanilla': if world.shuffle[player] == 'vanilla':
@@ -1387,15 +1446,15 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
elif startingstate.has('Fighter Sword', player): elif startingstate.has('Fighter Sword', player):
equip[0x359] = 1 equip[0x359] = 1
if startingstate.has('L5 Bombs', player): if startingstate.has('L5 Bombs', player) or startingstate.has('L5 Cane', player):
equip[0x38F] = 5 equip[0x38F] = 5
elif startingstate.has('L4 Bombs', player): elif startingstate.has('L4 Bombs', player) or startingstate.has('L4 Cane', player):
equip[0x38F] = 4 equip[0x38F] = 4
elif startingstate.has('L3 Bombs', player): elif startingstate.has('L3 Bombs', player) or startingstate.has('L3 Cane', player):
equip[0x38F] = 3 equip[0x38F] = 3
elif startingstate.has('L2 Bombs', player): elif startingstate.has('L2 Bombs', player) or startingstate.has('L2 Cane', player):
equip[0x38F] = 2 equip[0x38F] = 2
elif startingstate.has('L1 Bombs', player): elif startingstate.has('L1 Bombs', player) or startingstate.has('L1 Cane', player) or world.swords[player] == 'cane':
equip[0x38F] = 1 equip[0x38F] = 1
if startingstate.has('Mirror Shield', player): if startingstate.has('Mirror Shield', player):
@@ -1425,6 +1484,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
'Titans Mitts', 'Power Glove', 'Progressive Glove', 'Titans Mitts', 'Power Glove', 'Progressive Glove',
'Golden Sword', 'Tempered Sword', 'Master Sword', 'Fighter Sword', 'Progressive Sword', 'Golden Sword', 'Tempered Sword', 'Master Sword', 'Fighter Sword', 'Progressive Sword',
'L5 Bombs', 'L4 Bombs', 'L3 Bombs', 'L2 Bombs', 'L1 Bombs', 'Progressive Bombs', 'L5 Bombs', 'L4 Bombs', 'L3 Bombs', 'L2 Bombs', 'L1 Bombs', 'Progressive Bombs',
'L5 Cane', 'L4 Cane', 'L3 Cane', 'L2 Cane', 'L1 Cane', 'Progressive Cane',
'Mirror Shield', 'Red Shield', 'Blue Shield', 'Progressive Shield', 'Mirror Shield', 'Red Shield', 'Blue Shield', 'Progressive Shield',
'Red Mail', 'Blue Mail', 'Progressive Armor', 'Red Mail', 'Blue Mail', 'Progressive Armor',
'Magic Upgrade (1/4)', 'Magic Upgrade (1/2)']: 'Magic Upgrade (1/4)', 'Magic Upgrade (1/2)']:

View File

@@ -337,11 +337,11 @@ def global_rules(world, player):
set_rule(world.get_entrance('Mire Lobby Gap', player), lambda state: state.has_Boots(player) or state.has('Hookshot', player)) set_rule(world.get_entrance('Mire Lobby Gap', player), lambda state: state.has_Boots(player) or state.has('Hookshot', player))
set_rule(world.get_entrance('Mire Post-Gap Gap', player), lambda state: state.has_Boots(player) or state.has('Hookshot', player)) set_rule(world.get_entrance('Mire Post-Gap Gap', player), lambda state: state.has_Boots(player) or state.has('Hookshot', player))
set_rule(world.get_entrance('Mire Falling Bridge WN', player), lambda state: state.has_Boots(player) or state.has('Hookshot', player)) # this is due to the fact the the door opposite is blocked set_rule(world.get_entrance('Mire Falling Bridge WN', player), lambda state: state.has_Boots(player) or state.has('Hookshot', player)) # this is due to the fact the the door opposite is blocked
set_rule(world.get_entrance('Mire 2 NE', player), lambda state: state.bomb_mode_check(player, 1) and set_rule(world.get_entrance('Mire 2 NE', player), lambda state: state.special_weapon_check(player, 1) and
(state.has_real_sword(player) or (state.has_real_sword(player) or
(state.has('Fire Rod', player) and (state.can_use_bombs(player) or state.can_extend_magic(player, 9))) or # 9 fr shots or 8 with some bombs (state.has('Fire Rod', player) and (state.can_use_bombs(player) or state.can_extend_magic(player, 9))) or # 9 fr shots or 8 with some bombs
(state.has('Ice Rod', player) and state.can_use_bombs(player)) or # freeze popo and throw, bomb to finish (state.has('Ice Rod', player) and state.can_use_bombs(player)) or # freeze popo and throw, bomb to finish
state.has('Hammer', player) or state.has('Cane of Somaria', player) or state.can_shoot_arrows(player) or state.has_bomb_level(player, 1))) # need to defeat wizzrobes, bombs don't work ... state.has('Hammer', player) or state.has('Cane of Somaria', player) or state.can_shoot_arrows(player) or state.has_special_weapon_level(player, 1))) # need to defeat wizzrobes, bombs don't work ...
# byrna could work with sufficient magic # byrna could work with sufficient magic
set_rule(world.get_location('Misery Mire - Spike Chest', player), lambda state: (state.world.can_take_damage and state.has_hearts(player, 4)) or state.has('Cane of Byrna', player) or state.has('Cape', player)) set_rule(world.get_location('Misery Mire - Spike Chest', player), lambda state: (state.world.can_take_damage and state.has_hearts(player, 4)) or state.has('Cane of Byrna', player) or state.has('Cape', player))
set_rule(world.get_entrance('Mire Left Bridge Hook Path', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('Mire Left Bridge Hook Path', player), lambda state: state.has('Hookshot', player))
@@ -593,7 +593,7 @@ def global_rules(world, player):
set_rule( set_rule(
world.get_location('Ganon', player), world.get_location('Ganon', player),
lambda state: (state.has_real_sword(player, 2) or state.has_bomb_level(player, 3)) lambda state: (state.has_real_sword(player, 2) or state.has_special_weapon_level(player, 3))
and state.has_fire_source(player) and state.has_fire_source(player)
and state.has_crystals(world.crystals_needed_for_ganon[player], player) and state.has_crystals(world.crystals_needed_for_ganon[player], player)
and (state.has_real_sword(player, 3) or and (state.has_real_sword(player, 3) or
@@ -604,7 +604,7 @@ def global_rules(world, player):
set_rule( set_rule(
world.get_entrance('Ganon Drop', player), world.get_entrance('Ganon Drop', player),
lambda state: state.has_real_sword(player, 2) or state.has_bomb_level(player, 3)) lambda state: state.has_real_sword(player, 2) or state.has_special_weapon_level(player, 3))
# need to damage ganon to get tiles to drop # need to damage ganon to get tiles to drop
def bomb_rules(world, player): def bomb_rules(world, player):
@@ -860,6 +860,8 @@ def default_rules(world, player):
swordless_rules(world, player) swordless_rules(world, player)
if world.swords[player] == 'bombs': if world.swords[player] == 'bombs':
bomb_mode_rules(world, player) bomb_mode_rules(world, player)
if world.swords[player] in ['byrna', 'somaria', 'cane']:
cane_mode_rules(world, player)
if world.swords[player] in ['pseudo', 'assured_pseudo']: if world.swords[player] in ['pseudo', 'assured_pseudo']:
pseudo_sword_mode_rules(world, player) pseudo_sword_mode_rules(world, player)
@@ -1531,11 +1533,25 @@ def bomb_mode_rules(world, player):
set_rule(world.get_entrance('Tower Altar NW', player), lambda state: True) set_rule(world.get_entrance('Tower Altar NW', player), lambda state: True)
set_rule(world.get_entrance('Skull Vines NW', player), lambda state: True) set_rule(world.get_entrance('Skull Vines NW', player), lambda state: True)
set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_bomb_level(player, 2)) set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_special_weapon_level(player, 2))
set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_bomb_level(player, 2)) set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_special_weapon_level(player, 2))
if world.mode[player] != 'inverted': if world.mode[player] != 'inverted':
set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has_bomb_level(player, 2) or state.has('Beat Agahnim 1', player)) # barrier gets removed after killing agahnim, relevant for entrance shuffle set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has_special_weapon_level(player, 2) or state.has('Beat Agahnim 1', player)) # barrier gets removed after killing agahnim, relevant for entrance shuffle
set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock Ledge', 'Region', player)) # sword not required to use medallion in bomb-only
add_bunny_rule(world.get_entrance('Turtle Rock', player), player)
add_bunny_rule(world.get_entrance('Misery Mire', player), player)
def cane_mode_rules(world, player):
set_rule(world.get_entrance('Tower Altar NW', player), lambda state: True)
set_rule(world.get_entrance('Skull Vines NW', player), lambda state: True)
set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_special_weapon_level(player, 2))
set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_special_weapon_level(player, 2))
if world.mode[player] != 'inverted':
set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has_special_weapon_level(player, 2) or state.has('Beat Agahnim 1', player)) # barrier gets removed after killing agahnim, relevant for entrance shuffle
set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock Ledge', 'Region', player)) # sword not required to use medallion in bomb-only set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock Ledge', 'Region', player)) # sword not required to use medallion in bomb-only
add_bunny_rule(world.get_entrance('Turtle Rock', player), player) add_bunny_rule(world.get_entrance('Turtle Rock', player), player)

Binary file not shown.

View File

@@ -37,6 +37,9 @@
"pseudo", "pseudo",
"assured_pseudo", "assured_pseudo",
"bombs", "bombs",
"byrna",
"somaria",
"cane",
"vanilla" "vanilla"
] ]
}, },